2025位运算指南:15道LeetCode-Go题解从基础到进阶

2025位运算指南:15道LeetCode-Go题解从基础到进阶

【免费下载链接】LeetCode-Go 该内容是使用Go语言编写的LeetCode题目的完整解决方案集合,实现了100%的测试覆盖率,并且运行时间优于所有题目100%的提交结果。 【免费下载链接】LeetCode-Go 项目地址: https://gitcode.com/GitHub_Trending/le/LeetCode-Go

你是否还在为位运算题目抓耳挠腮?是否觉得那些&|^符号如同天书?本文将通过LeetCode-Go项目中15道经典位运算题目,带你掌握从基础操作到高级技巧的全套方法,让你在算法实践中轻松应对各类位运算难题。读完本文,你将能够:

  • 熟练运用位运算解决实际问题
  • 理解并掌握15种位运算技巧
  • 大幅提升算法性能,优化时间和空间复杂度

位运算基础:从理论到实践

位运算(Bit Manipulation)是程序设计中对整数的二进制表示进行操作的技术。在Go语言中,位运算操作符包括:&(与)、|(或)、^(异或)、<<(左移)和>>(右移)。这些操作看似简单,却能组合出各种高效的算法。

LeetCode-Go项目中提供了丰富的位运算工具类,例如template/BIT.go中的二进制索引树(Binary Indexed Tree)实现:

func (bit *BinaryIndexedTree) Add(index int, val int) {
    for ; index <= bit.capacity; index += index & -index {
        bit.tree[index] += val
    }
}

func (bit *BinaryIndexedTree) Query(index int) int {
    sum := 0
    for ; index > 0; index -= index & -index {
        sum += bit.tree[index]
    }
    return sum
}

这段代码巧妙地利用index & -index来获取最低位的1,实现了高效的前缀和查询与更新操作,时间复杂度均为O(log n)。

计数问题:位运算的拿手好戏

计算数字的二进制表示中1的个数

0338.Counting-Bits/338. Counting Bits.go提供了一种高效计算从0到n的每个数的二进制表示中1的个数的方法:

func countBits(num int) []int {
    bits := make([]int, num+1)
    for i := 1; i <= num; i++ {
        bits[i] += bits[i&(i-1)] + 1
    }
    return bits
}

这里的关键是i&(i-1)操作,它能够清除i二进制表示中的最后一个1。例如,当i=6(二进制110)时,i&(i-1)=110 & 101=100(4),这样我们就可以利用之前计算的结果,避免重复计算。

判断二进制数是否具有交替位

0693.Binary-Number-with-Alternating-Bits/693. Binary Number with Alternating Bits.go展示了如何判断一个数的二进制表示是否具有交替的0和1:

func hasAlternatingBits(n int) bool {
    n ^= n >> 1
    return (n & (n + 1)) == 0
}

这个解法非常巧妙。首先,将n与n右移1位的结果进行异或操作。如果n的二进制表示是交替的0和1,那么异或的结果将是全1。例如,n=5(101),n>>1=2(010),n^n>>1=111(7)。然后,我们检查这个结果加1是否为2的幂,即(n & (n + 1)) == 0

集合操作:位运算的高效应用

子集生成

0078.Subsets/78. Subsets.go中提到了使用位运算生成子集的方法:

// 解法三:位运算的方法
func subsets(nums []int) [][]int {
    result := make([][]int, 0)
    n := len(nums)
    // 总共有 2^n 个子集
    for i := 0; i < (1 << n); i++ {
        subset := make([]int, 0)
        for j := 0; j < n; j++ {
            // 检查第 j 位是否为 1
            if (i & (1 << j)) != 0 {
                subset = append(subset, nums[j])
            }
        }
        result = append(result, subset)
    }
    return result
}

这种方法的思路是,对于n个元素的集合,每个子集可以用一个n位的二进制数表示,其中第j位为1表示集合中包含第j个元素。

有效单词数统计

1178.Number-of-Valid-Words-for-Each-Puzzle/1178. Number of Valid Words for Each Puzzle.go展示了如何使用位运算来解决字符串匹配问题:

var bitMap uint32
for _, w := range word {
    bitMap |= (1 << (w - 'a')) // 将单词压缩为 bitMap
}

这里将每个单词压缩成一个32位的整数,其中每一位代表一个字母是否出现。这种方法不仅节省空间,还能利用位运算快速进行集合操作。

高级应用:位运算的奇思妙想

整数的补码

1009.Complement-of-Base-10-Integer/1009. Complement of Base 10 Integer.go展示了如何计算一个整数的补码:

func bitwiseComplement(n int) int {
    if n == 0 {
        return 1
    }
    mask := 1
    for mask <= n {
        mask <<= 1
    }
    return (mask - 1) ^ n
}

这里的关键是找到比n大的最小的2的幂,然后减1得到一个与n位数相同的全1掩码,最后与n进行异或操作得到补码。

设计位集

2166.Design-Bitset/2166. Design Bitset.go实现了一个位集数据结构,支持各种位操作:

type Bitset struct {
    bits []uint64
    size int
    cnt  int
    flip bool
}

func Constructor(size int) Bitset {
    return Bitset{
        bits: make([]uint64, (size+63)/64),
        size: size,
    }
}

func (this *Bitset) Fix(idx int) {
    pos, bit := idx/64, idx%64
    if this.flip {
        if (this.bits[pos] & (1 << bit)) != 0 {
            this.bits[pos] &^= 1 << bit
            this.cnt++
        }
    } else {
        if (this.bits[pos] & (1 << bit)) == 0 {
            this.bits[pos] |= 1 << bit
            this.cnt++
        }
    }
}

这个实现使用了uint64切片来存储位,每个uint64可以存储64个 bit,大大节省了空间。同时,通过一个flip标志,实现了O(1)时间复杂度的翻转操作。

总结与展望

位运算作为一种底层操作,在算法优化中有着广泛的应用。通过本文介绍的15道LeetCode题目,我们可以看到位运算能够大幅提升算法的时间和空间效率。无论是简单的计数问题,还是复杂的集合操作,位运算都能提供简洁而高效的解决方案。

LeetCode-Go项目中还有更多位运算的精彩应用,例如0190.Reverse-Bits/190. Reverse Bits.go中的位反转,0762.Prime-Number-of-Set-Bits-in-Binary-Representation/762. Prime Number of Set Bits in Binary Representation.go中的素数计数等。

掌握位运算不仅能够帮助你在算法实践中脱颖而出,还能让你写出更高效、更优雅的代码。希望本文介绍的技巧能够对你有所启发,快去LeetCode-Go项目中探索更多位运算的奥秘吧!

如果你觉得本文对你有帮助,请点赞、收藏、关注三连,我们下期再见!

【免费下载链接】LeetCode-Go 该内容是使用Go语言编写的LeetCode题目的完整解决方案集合,实现了100%的测试覆盖率,并且运行时间优于所有题目100%的提交结果。 【免费下载链接】LeetCode-Go 项目地址: https://gitcode.com/GitHub_Trending/le/LeetCode-Go

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值