位运算
注 : 本博客代码全程采用JAVA进行编写
位运算在解决经典算法问题中往往会产生事半工倍的效果,这都要取决于那些神奇的位运算规则,在开始之前,先来看两道经典位运算题目,感受一下位运算的伟大。
1.短路求值原理
题目描述: 计算1+2+3+4+……+n
要求:不准使用乘除法, if while等语句
class Solution{
public int getResult(int n){
boolean flag=(n>1) && ((n+=Sum_Solution(n-1))>0);
return n;
}
}
2. 不用加减乘除的加法
写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。
数据范围:两个数都满足 -10 ≤ n ≤ 1000−10≤n≤1000进阶:空间复杂度 O(1)O(1),时间复杂度 O(1)O(1)
解题思路:
//step1:按位与是查看两个数哪些二进制位都为1,这些都是进位位,结果需左移一位,表示进位后的结果
//step2:异或是查看两个数哪些二进制位只有一个为1,这些是非进位位,可以直接加、减,结果表示非进位位进行加操作后的结果
//step3:n1&n2是查看有没有进位位了,如果有,需要重复step1、step2;如果没有,保留n1、n2上二进制为1的部分,用或将之合为一个数,即为最后结果
public class Solution {
public int Add(int num1,int num2) {
while(num2!=0){
int temp=num1^num2; //拿出不需要进位的
num2=(num2&num1) << 1; //将需要进位的往前移动
num1=temp;
}
return num1;
}
}
上面两道题目都是在leetcode官网摘录的经典题目,如果没看懂也没有关系,接下来一部分会带着你从易到难掌握位运算的常见操作
3. 位运算常见操作
-
异或 ^:
- x与0异或为x
- x与x异或为0
- 满足交换律 结合律
-
2的幂
n&(n-1)==0 或者 (n&-n)==n
-
4的幂
(n&(n-1))==0 && n>0 && n%3==1
-
3的幂
n>0 && 1162261467 % n==0;
-
位1的个数
public class Solution { // you need to treat n as an unsigned value public int hammingWeight(int n) { int count=0; while(n!=0){ count++; n=n&(n-1); } return count; } }
-
交换数字
class Solution { public int[] swapNumbers(int[] numbers) { numbers[0]=numbers[0]^numbers[1]; numbers[1]=numbers[1]^numbers[0]; numbers[0]=numbers[0]^numbers[1]; return numbers; } }
解释:
-
class Solution { public int singleNumber(int[] nums) { int target=0; for(int nu:nums){ target=target^nu; } return target; } }
进阶: **只出现一次的数字 II (不会)
-
class Solution { public int hammingDistance(int x, int y) { //1. 相同的位置留0 不同的位置留1 x=x^y; int n=0; //2. 计算位置为1的个数 while(x != 0){ x=x&(x-1); n++; } return n; } }
-
**找出所有子集的异或总和再求和 (没思路)
class Solution { public int subsetXORSum(int[] nums) { int sum=0; int i=0,j=0,ans=0; for(i=0;i<(1<<nums.length);i++){ ans=0; for(j=0;j<nums.length;j++){ if((i & (1<<j)) !=0 ) ans^=nums[j]; } sum+=ans; } return sum; } }
-
**两整数之和 (好难理解)
问题转换为这个样子
class Solution { public int getSum(int a, int b) { // a=a^b; //不一样的地方为1 a=a&b //一样的地方为1 左移之后表示进位 while(b!=0){ int temp=a^b; //拿出不需要进位的 b=(a&b)<<1; a=temp; } return a; } } // 递归解决方式 : 更好理解--------- class Solution { public int getSum(int a, int b) { return b==0? a: getSum(a^b,(a&b)<<1); } }
-
class Solution { public int insertBits(int N, int M, int i, int j) { for(int p=i;p<=j;p++){ N &= ~((long) 1<<p); //每一位都搞成0 } return N | (M << i); } }