每天学习一点算法 2026/04/15
题目:两整数之和
给你两个整数
a和b,不使用 运算符+和-,计算并返回两整数之和。
不能使用 + - 运算符就只能使用位运算符了
顺便总结一下位运算符吧(不想看的可以直接跳到最后的解题处)
按位与(&)
按位与(&)运算符在两个操作数对应的二进位都为 1 时,该位的结果值才为 1(全为 1 才为 1,否则为 0)。
javascript
const a = 5; // 00000000000000000000000000000101
const b = 3; // 00000000000000000000000000000011
console.log(a & b); // 00000000000000000000000000000001
// Expected output: 1
按位或(|)
按位或(|)运算符在其中一个或两个操作数对应的二进制位为 1 时,该位的结果值为 1(有一个为 1 就为 1,全为 0 才为 0)
javascript
const a = 5; // 00000000000000000000000000000101
const b = 3; // 00000000000000000000000000000011
console.log(a | b); // 00000000000000000000000000000111
// Expected output: 7
按位异或(^)
按位异或(^)运算符在两个操作数有且仅有一个对应的二进制位为 1 时,该位的结果值为 1(相同为 0,不同为 1 )。
javascript
const a = 5; // 00000000000000000000000000000101
const b = 3; // 00000000000000000000000000000011
console.log(a ^ b); // 00000000000000000000000000000110
// Expected output: 6
我们可以看出不考虑进位的话,这就跟二进制数加法是一样的操作。
按位非(~)
按位非运算符(~)将操作数的位反转。如同其他位运算符一样,它将操作数转化为 32 位的有符号整型。(0 变 1,1 变 0)
注意:负数在计算机内是补码存储的
typescript
const a = 5; // 00000000000000000000000000000101
const b = -3; // 11111111111111111111111111111101
console.log(~a); // 11111111111111111111111111111010
// Expected output: -6
console.log(~b); // 00000000000000000000000000000010
// Expected output: 2
左移 (<<)
左移操作符 (<<) 将第一个操作数向左移动指定位数,左边超出的位数将会被清除,右边将会补零
typescript
const a = 5; // 00000000000000000000000000000101
const b = 2; // 00000000000000000000000000000010
console.log(a << b); // 00000000000000000000000000010100
// Expected output: 20
右移(>>)
右移运算符(>>)将一个操作数的二进制表示形式向右移动指定位数,该操作数可以是数值或者 BigInt 类型。右边移出位被丢弃,左边移出的空位补符号位(最左边那位)。该操作也称为"符号位传播右移"(sign-propagating right shift)或"算术右移"(arithmetic right shift),因为返回值的符号位与第一个操作数的符号位相同。
javascript
const a = 5; // 00000000000000000000000000000101
const b = 2; // 00000000000000000000000000000010
const c = -5; // 11111111111111111111111111111011
console.log(a >> b); // 00000000000000000000000000000001
// Expected output: 1
console.log(c >> b); // 11111111111111111111111111111110
// Expected output: -2
解题
然后我们回到这道题:
- 我们之前分析过,不考虑进位的话我们的 a ^ b 操作就跟加法操作的结果是一样的
- 我们又知道同为 1 的时候,会进一位,那我们用 a & b 操作得到结果就是每一位相加多出的需要进位 1 ,再执行左移操作就把 1 对应到了需要进位的位置上了
- 然后我们继续将第一步的结果和第二部的结果进行同样的操作,直到
a & b === 0表示在屋进位,此时的 a ^ b 就是最终的结果
typescript
function getSum(a: number, b: number): number {
// 循环执行位操作
while (b !== 0) {
const sum = a ^ b // 得到不考虑进位的和结果
const carry = (a & b) << 1 // 得到需要加上的进位
// 重新赋值 a b , 循环操作
a = sum
b = carry
}
return a // 返回最终结果
};
题目来源:力扣(LeetCode)