^ 按位异或运算符
本质上是无进位加法,例如:
0遇见1,1遇见0等于1
1遇见1,0遇见0等于0(不允许同性恋法则)
加法:0+1=1
1+0=1
0+0=0
1+1=0(进位)
所以位异或运算本质上就是不考虑进位的加法,在不考虑进位的加法异或运算符可以解决:
例如:9+4=13
9的补码 1001
4的补码 0100
异或结果 1101 转为十进制就等于13
但是遇到需要进位的场景则无法准确运算,则需要考虑进位的情况。
&按位与运算符:
可以用来获取二进制加法是否进位,举例说明:
1遇见1=1
1遇见0,0遇见1,0遇见0=0
加法中:1+1=0(进位),
那么我们用与运算的思想就可以推出:与运算等于1的位置发生了进位
举例:
8+9=17
1、先异或运算(无进位加法)计算加法
8^9(异或运算符)计算:
8的补码 1000
9的补码 1001
8^9补码 0001
转换为十进制位等于1(值A)
2、再用与运算判断是否进位
8&9计算:
8的补码 1000
9的补码 1001
与运算 1000,
说明第一个1发生了进位,那么我们在此左移一位变为10000,结果等于16(值B)。
因为发生了进位,则再需要用无进位加法的结果(值A)+进位后结果(值B)
也就是16+1
3、则再用异或运算(无进位加法)计算加法
16的补码 10000
1的补码 00001
异或运算 10001 等于17
4、再次用与运算判断是否需要进位:
16的补码 10000
1的补码 00001
与运算 00000 等于0,
说明无进位,则无需用无进位加法结果再次累加进位结果
总结:
1、每发生一次加法,则先用无进位加法算出无进位加法结果(值A)
2、然后用与运算判断是否发生进位
-
- 有进位则用算出的结果右移一位变成需要新加的结果(值B),转入下述3
- 无进位则加法结果就等于值A,无需下述3
3、再计算A+B的无进位加法
4、再判断A+B是否进位...
JAVA解法
class Solution {
public int add(int a, int b) {
while(b!=0){
int add = (a&b) 1;
a = a^b;
b = add;
}
return a;
}
}
python解法
题目要求结果不会溢出 32 位整数,因为python的int类型位无限长的补码表示,所以python语言需要考虑边界
class Solution:
def add(self, a: int, b: int) -> int:
# 表示32位最大的补码
x = 0xffffffff
# 求32位内的a、b
a,b = a & x, b & x
while(b!=0):
carry = (a & b) 1 & x
a = a ^ b
b = carry
# k = 0x7fffffff 表示32位内最大整数,32位为符号位
#若为负数,则对32位以内的数字取反,然后再对整体取反
return a if a 0x7fffffff else ~(a ^ x)
扩展知识:要求实现减法、乘法、除法
减法:很简单,就是把b改成-b,然后再相加就可以了
JAVA实现:
class Solution {
public int sub(int a,int b){
//取反+1则等于负数本身,也就是负b,~是对所有补码取反,包括符号位
b = add(~b,1);
add(a,b);
}
public int add(int a, int b) {
while(b!=0){
int add = (a&b) 1;
a = a^b;
b = add;
}
return a;
}
}
为什么 ~b +1等于负b呢?
假设b等于1,则原码、反码补码等于
0000 0000 0000 0000 0000 0000 0000 0001
-1的原码等于
1000 0000 0000 0000 0000 0000 0000 0001
反码等于
1111 1111 1111 1111 1111 1111 1111 1110
补码等于
1111 1111 1111 1111 1111 1111 1111 1111
那么~b就等于-1的反码,再加一个1就等于-1的补码,计算机内部都是用补码进行运算,故而相等