位运算
- 基础公式:
x^x=0、x&(x-1)(消最右 1)、x&1(奇偶)是核心中的核心; - 高频技巧:lowbit 公式(
x&-x)、2 的幂判断(x&(x-1)==0)、异或交换数需熟练; - 实战场景:唯一数、统计 1 的个数、矩阵区域和(结合位运算)等场景直接套用对应公式。
x ^ 0 = x |
任何数异或 0 等于自身 | 101 ^ 000 = 101 |
|---|---|---|
x ^ x = 0 |
任何数异或自身等于 0(核心!) | 101 ^ 101 = 000 |
x & 0 = 0 |
任何数与 0 等于 0 | 101 & 000 = 000 |
x & x = x |
任何数与自身等于自身 | 101 & 101 = 101 |
x & 1 = 1 → 奇数
**(x >> k) & 1**-> 获取 x 的第 k 位(从 0 开始,最低位是第 0 位)
- 统计二进制中 1 的个数、判断某一位是否为 1
x & ~(1 << k)->将 x 的第 k 位设为 0(其他位不变)
- 取消标记、清除某一位
x & (1 << k) != 0 ->判断 x 的第 k 位是否为 1
- 状态检查
x & (x - 1)---> 消除 x 的二进制中「最右边的 1」
- 统计 1 的个数、判断是否为 2 的幂
**x & -x**-> 提取 x 的二进制中「最右边的 1」
- 树状数组、拆分二进制位 、
x & (x - 1) == 0-> 判断 x 是否为 2 的幂(x>0)
- 2 的幂数识别
必会:
x: 1010000
x-1: 1001111
x&(x-1) 1000000
常用操作
1. 交换两个数(无需临时变量)
- 面试常考,无临时变量交换数值(注意:a 和 b 不能指向同一内存地址)
java
// 核心:a ^ b ^ b = a,a ^ a ^ b = b
a = a ^ b;
b = a ^ b; // 等价于 (a^b)^b = a
a = a ^ b; // 等价于 (a^b)^a = b
2.找数组中唯一出现一次的数(其他数出现两次)
- 核心逻辑 :
x ^ x = 0,0 ^ x = x,两次出现的数异或抵消,最终剩下唯一数。
java
int res = 0;
for (int num : nums) res ^= num;
return res;
3. 统计二进制中 1 的个数
java
int count = 0;
while (x != 0) {
x = x & (x - 1); // 消除最右边的1
count++;
}
return count;
4. 快速计算绝对值(无分支)
java
int sign = x >> 31; // 最高位:正数0,负数-1(补码)
int abs = (x ^ sign) - sign;
面试题 01.01. 判定字符是否唯一

java
class Solution {
public boolean isUnique(String astr) {
int n=astr.length();
if(n>26) return false;
int bitmap=0; //只用整型变量(26个长度)
for(int i=0;i<n;i++){
int idx=astr.charAt(i)-'a'; //第几个位置
//取第idx位看看是1还是0
//1:该字符在 0 表不在
if(((bitmap>>idx)&1)==1) return false; //存在
//不存在,就得把第idx位设置为1,添加存在
else bitmap=bitmap|(1<<idx);
//100
//010
//110(设置第三位为1)
}
return true;
}
}
268. 丢失的数字
利用这两个公式:x^x=0 0^x=x
- 自己补0-n的数出来
java
class Solution {
public int missingNumber(int[] nums) {
// x^x=0 0^x=x
int n=nums.length;
int ret=0;
//[0,n-1]
for(int i=0;i<n;i++){
ret=ret^nums[i];
ret=ret^i;
}
ret=ret^n; //n
return ret;
}
}
136. 只出现一次的数字(同上)
对数组所有元素进行异或^的值就是最终结果。注:两个值不同,则异或结果为1;两个值相同,异或结果为0。
java
class Solution {
public int singleNumber(int[] nums) {
// x^x=0 0^x=x
int n=nums.length;
int ret=0;
//[0,n-1]
for(int i=0;i<n;i++){
ret=ret^nums[i];
}
return ret;
}
}
338. 比特位计数
java
class Solution {
public int[] countBits(int n) {
int[] ret=new int[n+1];
for(int i=0;i<=n;i++){
//统计1的个数
ret[i]=oneCnt(i);
}
return ret;
}
//统计一个数二进制1的个数
public int oneCnt(int n){
//1010
int cnt=0;
while(n!=0){
if((n&1)==1) cnt++;
n=n>>1;
}
return cnt;
}
}
统计函数修改为这样,更优雅
java
public int oneCnt(int n){
//1010
int cnt=0;
while(n!=0){
n=n&(n-1);//去掉最右边的1
cnt++;
}
return cnt;
}
最优解法(DP + 位运算,O (n))
利用位运算的规律优化,核心思路是「状态转移」:
核心规律:
对于任意整数 i:
- 如果
i是偶数 →i = 2 * (i/2)→ 二进制是i/2左移 1 位(末尾加 0)→ 1 的个数和i/2相同 →dp[i] = dp[i/2]; - 如果
i是奇数 →i = 2 * (i/2) + 1→ 二进制是i/2左移 1 位 + 末尾加 1 → 1 的个数 =i/2的个数 + 1 →dp[i] = dp[i/2] + 1。
简化公式(用位运算替代除法 / 取模):
i/2等价于i >> 1(右移 1 位);i是奇数等价于i & 1 == 1(最后一位是 1);→ 最终状态转移方程:dp[i] = dp[i >> 1] + (i & 1)。
java
class Solution {
public int[] countBits(int n) {
int[] dp = new int[n + 1];
for (int i = 1; i <= n; i++) { // 0的1的个数是0,从1开始算
dp[i] = dp[i >> 1] + (i & 1); // 核心公式
}
return dp;
}
}
461. 汉明距离
核心转化(关键一步)
两个数二进制位「不同」→ 对应位异或(^)结果为 1,「相同」则为 0。因此:
- 第一步:计算
x ^ y(记为num),得到一个数,其二进制中「1 的位置」就是 x 和 y 不同的位; - 第二步:统计
**num**中 1 的个数,就是汉明距离。
java
class Solution {
public int hammingDistance(int x, int y) {
//对应位置异或
//1.不同为1 2.相同为0
//本质数多少个1
int num=x^y;
int cnt=0;
while(num!=0){
num=num&(num-1); //去掉最右边1
cnt++;
}
return cnt;
}
}