第8周 位运算、布隆过滤器和LRU缓存、排序算法

2021-12-20
7分钟阅读时长

题目数量:12

第16课 | 位运算

1. 位运算基础及实战要点

参考链接

2. 位运算实战题目解析

参考链接

实战题目 / 课后作业

// 最优写法
func hammingWeight(num uint32) (cnt int) {
    for num > 0 {
        cnt++
        num &= num - 1
    }
    return cnt
}

// O(n) n = 32
func hammingWeight(num uint32) (cnt int) {
    for num > 0 {
        cnt += int(num & 1)
        num >>= 1
    }
    return cnt
}
func isPowerOfTwo(n int) bool {
    return n > 0 && n & (n - 1) == 0
}
// 没有上面运行快
func isPowerOfTwo(n int) bool {
    return n > 0 && n & -n == n
}
//方案二: 判断是否为最大 22 的幂的约数
func isPowerOfTwo(n int) bool {
    const big = 1 << 30
    return n > 0 && big%n == 0
}
// 写法一:
func reverseBits(n uint32) (ans uint32) {
    pos := 31
    for n > 0 {
        if n & 1 == 1 {
            ans |= 1 << pos
        }
        pos -= 1
        n >>= 1
    }
    return ans
}
// 写法二:
func reverseBits1(n uint32) (ans uint32) {
    for i := 0; i < 32; i++ {
        ans |= (n & 1) << (31 - i)
        n >>= 1
    }
    return ans
}
func solveNQueens(n int) (res [][]string) {
    size := 1 << n - 1
    var solve func(row, cols, pie, na int, queens []int)
    solve = func(row, cols, pie, na int, queens []int) {
        if row == n {
            ans := make([]string, n)
            for i := 0; i < n; i++ {
                c := ""
                for j := 0; j < n; j++ {
                    if queens[i] & (1 << j) > 0 {
                        c += "Q"
                    } else {
                        c += "."
                    }
                }
                ans[i] = c
            }
            res = append(res, ans)
            return
        }
        bits := size & (^(cols | pie | na))
        for bits > 0 {
            p := bits & -bits
            queens = append(queens, p)
            solve(row + 1, cols | p, (pie | p) << 1, (na | p) >> 1, queens)
            queens = queens[:len(queens) - 1]
            bits &= bits - 1
        }
    }
    solve(0, 0, 0, 0, []int{})
    return res
}
func totalNQueens(n int) (cnt int) {
    size := 1 << n - 1
    var slove func(int, int, int, int)
    slove = func(row, cols, pie, na int) {
        if row == n {
            cnt++
            return
        }
        bits := size & (^(cols | pie | na))
        for bits > 0 {
            p := bits & (-bits)
            bits &= bits - 1
            slove(row + 1, cols | p, (pie | p) << 1, (na | p) >> 1)
        }
    }
    slove(0 , 0, 0, 0)
    return cnt
}
// 方法一:Brian Kernighan 算法 等于暴力 计算每个数
// 方法二:动态规划——最高有效位
// 方法三:动态规划——最低有效位
func countBits(n int) []int {
    bits := make([]int, n + 1)
    for i := 1; i <= n; i++ {
        bits[i] = bits[i >> 1] + (i & 1)
    }
    return bits
}
// 方法四:动态规划——最低设置位
func countBits(n int) []int {
    bits := make([]int, n + 1)
    for i := 1; i <= n; i++ {
        bits[i] = bits[i & (i - 1)] + 1
    }
    return bits
}

第17课 | 布隆过滤器和LRU缓存

1. 布隆过滤器的实现及应用

参考链接

2. LRU Cache的实现、应用和题解

参考链接

实战题目 / 课后作业

func init() { debug.SetGCPercent(-1) } // 提升速度为 288ms, 没有开启之前为:516ms
type cacheNode struct {
    key int
    val int
    pre *cacheNode
    next *cacheNode
}

type LRUCache struct {
    capacity int
    mp map[int]*cacheNode
    head *cacheNode
    tail *cacheNode
}


func Constructor(capacity int) LRUCache {
    lru := LRUCache{
        capacity: capacity,
        mp: make(map[int]*cacheNode, capacity),
        head: &cacheNode{},
        tail: &cacheNode{},
    }
    lru.head.next = lru.tail
    lru.tail.pre = lru.head
    return lru
}


func (this *LRUCache) Get(key int) int {
    if node, ok := this.mp[key]; ok {
        this.moveToTail(node, node.val)
        return node.val
    }
    return -1
}


func (this *LRUCache) Put(key int, value int)  {
    if node, ok := this.mp[key]; ok {
        this.moveToTail(node, value)
    } else {
        if len(this.mp) == this.capacity {
            delNode := this.head.next
            this.deleteNode(delNode)
            delete(this.mp, delNode.key)
        }
        node = &cacheNode{key:key, val:value}
        this.addToTail(node)
        this.mp[key] = node
    }
}

func (this *LRUCache) moveToTail(node *cacheNode, value int) {
    this.deleteNode(node)

    node.val = value
    this.addToTail(node)
}

func (this *LRUCache) deleteNode(node *cacheNode) {
    node.next.pre = node.pre
    node.pre.next = node.next
}

func (this *LRUCache) addToTail(node *cacheNode) {
    this.tail.pre.next = node
    node.next = this.tail
    node.pre = this.tail.pre
    this.tail.pre = node
}

/**
 * Your LRUCache object will be instantiated and called as such:
 * obj := Constructor(capacity);
 * param_1 := obj.Get(key);
 * obj.Put(key,value);
 */

第8周 第18课 | 排序算法

1. 初级排序和高级排序的实现和特性

参考链接

课后作业

用自己熟悉的编程语言,手写各种初级排序代码,提交到第 8 周学习总结中。

2. 特殊排序及实战题目详解

参考链接

实战题目 / 课后作业

// 自定义排序 sort.Slice()
// 计数排序
func relativeSortArray(arr1 []int, arr2 []int) []int {
    ans := make([]int, 0, len(arr1))
    cnt := make([]int, 1001)
    for _, n := range arr1 {
        cnt[n]++
    }
    for _, n := range arr2 {
        for cnt[n] > 0 {
            ans = append(ans, n)
            cnt[n]--
        }
    }
    for i := 0; i < 1001; i++ {
        for cnt[i] > 0 {
            ans = append(ans, i)
            cnt[i]--
        }
    }
    return ans
}
// 方法一:对s, t进行排序比较
func isAnagram(s, t string) bool {
    s1, s2 := []byte(s), []byte(t)
    sort.Slice(s1, func(i, j int) bool { return s1[i] < s1[j] })
    sort.Slice(s2, func(i, j int) bool { return s2[i] < s2[j] })
    return string(s1) == string(s2)
}
// 方法二:hash计数
func isAnagram(s string, t string) bool {
    if len(s) != len(t) {
        return false
    }
    mp := make([]int, 26)
    for i, c := range s {
        mp[c - 'a']++
        mp[t[i] - 'a']--
    }
    for _, v := range mp {
        if v != 0 {
            return false
        }
    }
    return true
}

https://hwchang0417.wordpress.com/2019/11/04/leetcode-1244-design-a-leaderboard/

题目说明地址

func merge(intervals [][]int) (res [][]int) {
    if len(intervals) < 2 {
        return intervals
    }
    sort.Slice(intervals, func(i, j int) bool {
        return intervals[i][0] < intervals[j][0]
    })
    res = append(res, intervals[0])
    for i, j := 1, 0; i < len(intervals); i++ {
        if res[j][1] < intervals[i][0] {
            j++
            res = append(res, intervals[i])
        } else {
            res[j][1] = max(res[j][1], intervals[i][1])
        }
    }
    return res
}
func max(a, b int) int {
    if a > b {
        return a
    }
    return b
}
// 方法一:归并排序
func reversePairs(nums []int) int {
    return mergeSort(nums, 0, len(nums) - 1)
}
func mergeSort(nums []int, left int, right int) int {
    if left >= right {
        return 0
    }
    mid := left + (right - left) >> 1
    cnt := mergeSort(nums, left, mid) + mergeSort(nums, mid + 1, right)
    // 计算翻转对,并归并
    cache := make([]int, right - left + 1)
    c, i, l := 0, left, left
    for j := mid + 1; j <= right; j, c = j + 1, c + 1 {
        for i <= mid && nums[i] <= nums[j] * 2 {
            i++
        }
        for ; l <= mid && nums[l] < nums[j]; l, c = l + 1, c + 1 {
            cache[c] = nums[l]
        }
        cache[c] = nums[j]
        cnt += mid - i + 1 // l -> mid 是 ok 的
    }
    for ; l <= mid; l, c = l + 1, c + 1 {
        cache[c] = nums[l]
    }
    // 合并
    for i, n := 0, right - left + 1; i < n; i++ {
        nums[left + i] = cache[i]
    }
    return cnt
}
// 方法二:树状数组

本周作业及下周预习

本周作业

简单

中等

困难

下周预习

预习知识点:

预习题目: