Bootstrap

⭐算法OJ⭐位操作用法总结+实战指南(C++实现)

位操作在OJ 题目中是一种非常高效的工具,常用于优化时间复杂度和空间复杂度。本文是位操作在 OJ 题目中的主要用法总结,并以 C++ 实现为例。

相关题目:《C++⭐算法OJ⭐Single Number 系列(位操作)》

1. 基本位操作

(1) 与运算 (&)

用于提取某些二进制位。

示例:提取最低 4 位:

int num = 0b11011010;
int lower4 = num & 0b1111; // 结果为 0b1010

(2) 或运算 (|)

用于设置某些二进制位。

示例:设置第 3 位为 1:

int num = 0b11011010;
num = num | (1 << 2); // 结果为 0b11011110

(3) 异或运算 (^)

用于翻转某些二进制位。

示例:翻转第 4 位:

Copy
int num = 0b11011010;
num = num ^ (1 << 3); // 结果为 0b11010010

(4) 取反运算 (~)

用于翻转所有二进制位。

示例:

int num = 0b11011010;
num = ~num; // 结果为 0b00100101(假设 int 为 8 位)

(5) 左移 (<<) 和右移 (>>)

左移:将二进制位向左移动,低位补 0。

右移:将二进制位向右移动,高位补 0(逻辑右移)或补符号位(算术右移)。

示例:

int num = 0b11011010;
int leftShifted = num << 2; // 结果为 0b1101101000
int rightShifted = num >> 2; // 结果为 0b00110110

2. 常见应用场景

(1) 判断奇偶性

利用最低位是否为 1 来判断奇偶性。

示例:

bool isOdd(int num) {
    return num & 1; // 如果结果为 1,则是奇数
}

(2) 交换两个数

利用异或运算交换两个数,无需额外空间。

示例:

void swap(int &a, int &b) {
    a = a ^ b;
    b = a ^ b;
    a = a ^ b;
}

(3) 统计二进制中 1 的个数

利用 n & (n - 1) 每次消除最低位的 1。

示例:

int countOnes(int num) {
    int count = 0;
    while (num) {
        num = num & (num - 1); // 消除最低位的 1
        count++;
    }
    return count;
}

(4) 判断一个数是否是 2 的幂

2 的幂的二进制表示中只有一个 1。

示例:

bool isPowerOfTwo(int num) {
    return num > 0 && (num & (num - 1)) == 0;
}

(5) 找到最低位的 1

利用 n & -n 可以找到最低位的 1。

示例:

int lowestBit(int num) {
    return num & -num;
}

(6) 快速乘除 2 的幂

左移 1 位相当于乘以 2,右移 1 位相当于除以 2。

示例:

int multiplyByTwo(int num) {
    return num << 1;
}
int divideByTwo(int num) {
    return num >> 1;
}

3. 高级应用

(1) 状态压缩

利用二进制位表示状态,常用于动态规划或回溯算法。

示例:表示集合的子集:

int subset = 0b1010; // 表示集合 {1, 3}

(2) 枚举子集

利用位运算枚举集合的所有子集。

示例:

void enumerateSubsets(int set) {
    for (int subset = set; subset; subset = (subset - 1) & set) {
        // 处理子集
    }
}

(3) 快速幂算法

利用位运算加速幂运算。

示例:

int fastPow(int base, int exponent) {
    int result = 1;
    while (exponent) {
        if (exponent & 1) result *= base;
        base *= base;
        exponent >>= 1;
    }
    return result;
}

(4) 查找只出现一次的数字

利用异或运算找出数组中只出现一次的数字。

示例:

int singleNumber(vector<int>& nums) {
    int result = 0;
    for (int num : nums) result ^= num;
    return result;
}

(5) 查找两个只出现一次的数字

利用异或运算和分组思想。

示例:

vector<int> singleNumber(vector<int>& nums) {
    int xorResult = 0;
    for (int num : nums) xorResult ^= num;
    int mask = 1;
    while ((xorResult & mask) == 0) mask <<= 1;
    int num1 = 0, num2 = 0;
    for (int num : nums) {
        if (num & mask) num1 ^= num;
        else num2 ^= num;
    }
    return {num1, num2};
}

4. 总结

位操作在 OJ 题目中的主要用途包括:

  • 高效计算:如快速幂、统计 1 的个数。

  • 状态表示:如状态压缩、枚举子集。

  • 优化空间:如交换两个数、判断奇偶性。

  • 解决特定问题:如查找只出现一次的数字。

;