算法笔试-位运算

关于语言:一刷用 Golang,二刷用 Rust

题单来源于:分享丨【题单】位运算(基础/性质/拆位/试填/恒等式/思维)

位运算

集合可以用二进制表示,从低到高\(i\) 位为 \(1\) 表示 \(i\) 在集合中。例如集合 \(\{ 0, 2, 3 \}\) 可以用二进制数 \(1101_{(2)}\) 表示;反之 $ 1101_{(2)}$ 对应着集合 \(\{ 0, 2, 3 \}\)

也就是说,包含非负整数的集合 \(S\) 可以压缩成一个数字。

集合与集合:& 表示按位与,| 表示按位或,\(\oplus\) 表示按位异或,~ 表示按位取反,对称差指仅在其中一个集合的元素。

术语 集合 位运算
交集 \(A \cap B\) \(a \& b\)
并集 \(A \cup B\) \(a | b\)
对称差 \(A \bigtriangleup B\) \(a \oplus b\)
\(A \backslash B\) \(a \& \sim b\)

集合与元素

术语 集合 位运算
属于 \(i \in S\) \((s >> i) \& 1 = 1\)
不属于 \(i \notin S\) \((s >> i) \& 1 = 0\)
添加元素 \(S \cup \{ i\}\) s | (1 << i)
删除元素 \(S \backslash \{i\}\) s & ~ (1 << i)
删除最小元素 s & (s-1)

库函数: |术语|Python|Java|C++|Go| |---|------|----|---|---| |集合大小|s.bit_count()|Integer.bitcount(s)|__builtin_popcount(s)|bits.OnesCount(s)| |二进制长度(减一得到集合中的最大元素)|s.bit_length()|32-Integer.numberOfLeadingZeros(s)|32-__builtin_clz(s)|bits.Len(s)| |集合中的最小元素|(s&-s).bit_length()-1|Integer.numberOfTrailingZeros(s)|__builtin_ctz(s)|bits.TrailingZeros(s)|

遍历集合:设元素范围从 \(0\)\(n-1\),挨个判断是否在集合 \(s\) 中:

for (int i = 0; i < n; i++) {
    if ((s >> i) & 1) { // i 在 s 中
        // 处理 i 的逻辑
    }
}

枚举集合:设元素范围从 \(0\)\(n-1\),从空集枚举到全集:

for (int s = 0; s < (1 << n); s++) {
	// 处理 s 的逻辑
}

设集合为 \(s\)从大到小枚举 \(s\) 的所有非空子集 \(sub\)

for (int sub = s; sub; sub = (sub - 1) & s) {
	// 处理 sub 的逻辑
}

题单

题目 来源 难度 分数
3370. 仅含置位位的最小整数 第 426 场周赛 Q1 简单 1199
3226. 使两个整数相等的位更改次数 第 407 场周赛 Q1 简单 1247
1356. 根据数字二进制下 1 的数目排序 第 20 场双周赛 Q1 简单 1258
461. 汉明距离 简单
476. 数字的补数 简单
868. 二进制间距 第 93 场周赛 Q1 简单 1307
3211. 生成不含相邻零的二进制字符串 第 405 场周赛 Q2 中等 1353
2917. 找出数组中的 K-or 值 第 369 场周赛 Q1 简单 1389
693. 交替位二进制数 简单
2657. 找到两个数组的前缀公共数组 第 103 场周赛 Q2 中等 1304
231. 2 的幂 简单

题解

3370. 仅含置位位的最小整数

func smallestNumber(n int) int {
    return 1 << bits.Len(uint(n)) - 1
}

3226. 使两个整数相等的位更改次数

func minChanges(n int, k int) int {
    if n & k != k {
        return -1
    } 
    return bits.OnesCount(uint(n ^ k))
}

1356. 根据数字二进制下 1 的数目排序

func sortByBits(arr []int) []int {
    sort.Slice(arr, func (i, j int) bool {
        a := bits.OnesCount(uint(arr[i]))
        b := bits.OnesCount(uint(arr[j]))
        if a != b {
            return bits.OnesCount(uint(arr[i])) < bits.OnesCount(uint(arr[j]))
        }
        return arr[i] < arr[j]
    }) 
    return arr
}

461. 汉明距离

func hammingDistance(x int, y int) int {
    return bits.OnesCount(uint(x ^ y))
}

476. 数字的补数

func findComplement(num int) int {
    return 1 << bits.Len(uint(num)) - 1 - num
}

868. 二进制间距

func binaryGap(n int) int {
    i, idx, ans := 0, -1, 0
    for ; n > 0; n = n >> 1 {
        if n & 1 == 1 {
            if idx != -1 {
                ans = max(ans, i - idx)
            }
            idx = i
        }
        i++
    }
    return ans
}

3211. 生成不含相邻零的二进制字符串

func validStrings(n int) []string {
    ans := make([]string, 0)
    var dfs func (pos int, path []byte)
    dfs = func (pos int, path []byte) {
        if pos >= n {
            ans = append(ans, string(path))
            return
        }
        path[pos] = '1'
        dfs(pos + 1, path)
        
        if pos == 0 || path[pos-1] == '1' {
            path[pos] = '0'
            dfs(pos + 1, path)
        }
    }
    dfs(0, make([]byte, n))
    return ans
}

2917. 找出数组中的 K-or 值

func findKOr(nums []int, k int) int {
    cnt := make([]int, 31)
    for i := 0; i < 31; i++ {
        for _, v := range nums {
            if (v >> i) & 1 == 1 {
                cnt[i]++
            }
        }
    }
    ans := 0
    for i := 30; i >= 0; i-- {
        if cnt[i] >= k {
            fmt.Println(i)
            ans |= 1
        }
        if i != 0 {
            ans <<= 1
        }
    }
    return ans
}

693. 交替位二进制数

func hasAlternatingBits(n int) bool {
    t := n & 1
    n >>= 1
    for ; n > 0; n >>= 1 {
        if t == n & 1 {
            return false
        }
        t = n & 1
    }
    return true
}

2657. 找到两个数组的前缀公共数组

func findThePrefixCommonArray(A []int, B []int) []int {
    var q, p uint
    ans := make([]int, len(A))
    for i := 0; i < len(A); i++ {
        a, b := A[i], B[i]
        q |= (1 << a)
        p |= (1 << b)
        ans[i] = bits.OnesCount(q & p)
    }
    return ans
}

231. 2 的幂

func isPowerOfTwo(n int) bool {
    return bits.OnesCount(uint(n)) == 1
}