四,位运算算法实例

示例 1: LeetCode 的 Missing Number:

(1) 题目描述:

给定一个从 0 到 n 没有重复数字组成的数组,其中有一个数字漏掉了,请找出该数字。 要求:算法具有线性的时间复杂度,并且只占用常数的额外空间复杂度。

(2) 题目分析

  • 思路一:对数据进行排序,然后依次扫描,便能找出漏掉的数字。

    • 缺点:基于比较的排序算法的时间复杂度至少是 O(nlogn),不满足题目要求。

  • 思路二:先对 0 到 n 求和,记为 sum1,再对给定的数组求和,记为 sum2,二者之差即为漏掉的数字。

  • 思路三:比加法更高效的运算是「按位异或 (XOR) 运算」。我们这里采用位运算来求解。

Tips: 按位异或 运算的一个重要性质: 做运算的两个数相同时,结果为 0,不相同时结果为1。这个性质可以扩展到多个数做按位异或运算。

(3) 复杂度:

  • 时间复杂度:O(n),空间复杂度:O(1)。

(4) 实例代码:

missingNumber.lua 文件:

示例 2:LeetCode 的 Power of Two:

(1) 题目描述:

给定一个整数,判断它是否为 2 的幂。

(2) 题目分析: 2 的整数幂的有一个重要特点: 2 的整数幂对应的二进制形式中只有一个位是 1。 所以我们要做的就是判断输入的这个数的二进制形式是否符合这一条件。

注意:当输入的数为负数时,一定不是 2 的幂。

(3) 复杂度:

  • 时间复杂度:O(n),空间复杂度:O(1)。

isPowerOfTwo.lua 文件:

示例 3:LeetCode 的 Number of 1 Bits:

(1) 题目描述:

给定一个整数,求出它的二进制形式所包含 1 的个数。

例如,32 位整数 11 的二进制形式为 00000000000000000000000000001011,那么函数返回 3。

(2) 题目分析: 设输入的数为 num,把 num 与 1 做二进制的 按位与 (AND) 运算,即可判断它的最低位是否为 1。

(3) 解法一: 如果最低位为 1 的话,把计算变量加一,然后把 num 向右移动一位,重复上述操作。 当 num 变为 0 时,终止算法,输出结果。

(4) 复杂度:

  • 时间复杂度:O(log2v),log2v 为二进制数的位数,空间复杂度:O(1)。

numberOf1Bits-1.lua 文件:

(5) 解法二: n & (n - 1) 可以消除最后一个 1,所以用一个循环不停地消除 1 同时计数,直到 n 变成 0 为止。

(6) 复杂度:

  • 时间复杂度:O(m),m 为数字 num 的二进制表示形式中 1 的个数,空间复杂度:O(1)。

numberOf1Bits-2.lua 文件:

示例 4:Eratosthenes 筛法(素数筛)的一个实现

该算法可以计算出 [1, N] 区间内素数的个数。

Lua BitOp 相当快。在安装了标准 Lua 的 3GHz CPU 上,该程序可以在不到 90 毫秒的时间内运行完毕,但是执行了超过 100 万次的位函数调用。如果您想要更高的速度,请查看 LuaJIT

参考资料

Last updated