在看位运算相关LeetCode题之前,先放个传送门 常见位运算符及规律...
191. 位1的个数¹
编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。
示例 1:
输入:00000000000000000000000000001011
输出:3
解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。
示例 2:
输入:00000000000000000000000010000000
输出:1
解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。
示例 3:
输入:11111111111111111111111111111101
输出:31
解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。
解法一:位运算
- 思路:没啥说的,通过一个count记录1的个数,问题就落在了如何判断当前位是否为1((x << n) & 1)
- 复杂度:
- Time:O(1),循环的次数是确定(32),与数据规模无关
- Space:O(1)
public int hammingWeight(int n) {
int count = 0;
// 因为是4字节,所以长度是确定的:32位
for (int i = 0; i < 32; i++) {
// 判断当前位是否为1
if ((n & 1) != 0) count++;
// n 右移来将下一位放到最后
n >>= 1;
}
return count;
}
231. 2的幂¹
给定一个整数,编写一个函数来判断它是否是 2 的幂次方。
示例 1:
输入: 1
输出: true
解释: 20 = 1
示例 2:
输入: 16
输出: true
解释: 24 = 16
示例 3:
输入: 218
输出: false
解法一:暴力循环
- 思路:不断除2,直到除不了2(%2 != 0),然后判断这个奇数是否为1
- 复杂度:
- Time:O(n)
- Space:O(1)
public boolean isPowerOfTwo(int n) {
if (n == 0) return false;
while (n % 2 == 0) n /= 2;
return n == 1;
}
解法二:位运算
-
思路:若 n = 2^x 且 x 为自然数(即 n 为 2 的幂),则一定满足以下条件
- 恒有 n & (n - 1) == 0,这是因为:
- n 二进制最高位为 1,其余所有位为 0;比如 2º=0001,2¹=0010,2²=0100
- n - 1 二进制最高位为 0,其余所有位为 1;比如 2º-1=0000,2¹-1=0001,2²-1=0011
- 一定满足 n > 0
- 恒有 n & (n - 1) == 0,这是因为:
-
复杂度:
-
Time:O(1)
-
Space:O(1)
-
public boolean isPowerOfTwo(int n) {
return n > 0 ? (n & (n-1)) == 0 : false;
}
位运算符是直接就用二进制运算,不一定运算数就是二进制形式,也可以像本题是十进制形式;底层都是二进制运算
190. 颠倒二进制位¹
颠倒给定的 32 位无符号整数的二进制位。
示例 1:
输入: 00000010100101000001111010011100
输出: 00111001011110000010100101000000
解释: 输入的二进制串 00000010100101000001111010011100 表示无符号整数 43261596,
因此返回 964176192,其二进制表示形式为 00111001011110000010100101000000。
示例 2:
输入:11111111111111111111111111111101
输出:10111111111111111111111111111111
解释:输入的二进制串 11111111111111111111111111111101 表示无符号整数 4294967293,
因此返回 3221225471 其二进制表示形式为 10111111111111111111111111111111 。
解法一:转成字符串
- 思路:将数字变成字符串去操作
- 将 n 转化成String
- 对字符串进行逆序操作
- 将字符串还原成int
- 复杂度:
- Time:O(1)
- Space:O(1)
解法二:位运算
- 思路:可以通过位运算,得到n的每一位,然后逆序组织ans
- 从 n 的最低位开始,获取 n 的所有二进制位,并不断右移
- 从 ans 的最高位开始,加上n的二进制位,并不断左移
- 复杂度:
- Time:O(1)
- Space:O(1)
public int reverseBits(int n) {
int ans = 0;
for (int i = 0; i < 32; i++) {
ans = (ans << 1) + (n & 1); // ans左移,不断给低位赋值
n >>= 1; // n右移,不断获取高位
}
return ans;
}
371. 两整数之和¹
不使用运算符 + 和 - ,计算两整数 a 、b 之和。
示例 1:
输入: a = 1, b = 2
输出: 3
示例 2:
输入: a = -2, b = 3
输出: 1
解法一:位运算-迭代
-
思路:既然不能使用 + - ,那肯定就是用位运算
- 不进位加:( 0 0 = 0),(0 1 = 1),(1 0 = 1),(1 1 = 0)-----> 异或(^)
- 进位:(1 1 = 1),(0 1 = 0),(1 0 = 0),(0 0 = 0)-----> 与(&)------> 左移一位(<<)
====》sum + carry 就能得到结果,但不能 + ,所以不断重复以上步骤,直到carry=0(无进位)
-
复杂度:
- Time:O(n)
- Space:O(1)
public int getSum(int a, int b) {
while(b != 0) {
int sum = a ^ b; // 无进位加法结果
int carry = (a & b) << 1; // 进位值
a = sum; // 因为不能相加,所以再重复以上步骤
b = carry;
}
return a;
}
解法二:位运算-递归
public int getSum(int a, int b) {
return b == 0 ? a : getSum(a ^ b, (a & b) << 1);
}