位运算实现加法

📌 定义

不使用 + 和 - 运算符,使用位运算实现两个整数的加法。

示例:
输入: a = 1, b = 2
输出: 3

输入: a = -1, b = 1
输出: 0

输入: a = 5, b = 7
输出: 12

核心思路

利用异或和与运算模拟二进制加法:

  1. 异或(XOR):计算不考虑进位的和
  2. 与(AND)+ 左移:计算进位
  3. 重复:直到没有进位为止
示例: 5 + 7 = 12
二进制: 0101 + 0111 = 1100

步骤1:
  不带进位的和: 0101 ^ 0111 = 0010
  进位:        (0101 & 0111) << 1 = 0101 << 1 = 1010

步骤2:
  不带进位的和: 0010 ^ 1010 = 1000
  进位:        (0010 & 1010) << 1 = 0010 << 1 = 0100

步骤3:
  不带进位的和: 1000 ^ 0100 = 1100
  进位:        (1000 & 0100) << 1 = 0000 << 1 = 0000

进位为0,结果: 1100 (12)

复杂度分析

方法时间复杂度空间复杂度说明
迭代法O(log n)O(1)最多32次循环
递归法O(log n)O(log n)递归栈空间
查表法O(1)O(2^32)不现实

Go 代码

Go 实现

package main
 
import "fmt"
 
// 方法1: 迭代法
func getSum(a int, b int) int {
    for b != 0 {
        // 不带进位的和
        sum := a ^ b
 
        // 进位
        carry := (a & b) << 1
 
        a = sum
        b = carry
    }
 
    return a
}
 
// 方法2: 递归法
func getSumRecursive(a int, b int) int {
    if b == 0 {
        return a
    }
 
    // 不带进位的和
    sum := a ^ b
 
    // 进位
    carry := (a & b) << 1
 
    return getSumRecursive(sum, carry)
}
 
// 方法3: 处理32位整数
func getSum32(a int32, b int32) int32 {
    for b != 0 {
        sum := a ^ b
        carry := (a & b) << 1
        a = sum
        b = carry
    }
 
    return a
}
 
func main() {
    testCases := [][2]int{
        {1, 2},
        {5, 7},
        {-1, 1},
        {10, 20},
    }
 
    for _, tc := range testCases {
        a, b := tc[0], tc[1]
        result := getSum(a, b)
        fmt.Printf("%d + %d = %d\n", a, b, result)
    }
}

思路展开

二进制加法详解

半加器(不考虑进位输入):
A | B | Sum | Carry
--|---|-----|------
0 | 0 |  0  |  0
0 | 1 |  1  |  0
1 | 0 |  1  |  0
1 | 1 |  0  |  1

观察:
Sum = A ^ B(异或)
Carry = A & B(与)

完整示例:5 + 7

a = 5 (0101)
b = 7 (0111)

=== 第1次迭代 ===
sum = 0101 ^ 0111 = 0010
carry = (0101 & 0111) << 1
      = 0101 << 1
      = 1010

a = 0010
b = 1010

=== 第2次迭代 ===
sum = 0010 ^ 1010 = 1000
carry = (0010 & 1010) << 1
      = 0010 << 1
      = 0100

a = 1000
b = 0100

=== 第3次迭代 ===
sum = 1000 ^ 0100 = 1100
carry = (1000 & 0100) << 1
      = 0000 << 1
      = 0000

a = 1100
b = 0000

=== 结束 ===
b = 0,返回 a = 1100 (12)

负数处理详解

Python中整数无限长度,需要模拟32位:

正数示例: 5
  32位表示: 0000...0101
  MASK后:   0000...0101
  <= MAX_INT,直接返回

负数示例: -1 + 1
  -1的32位补码: 1111...1111
  1的32位:      0000...0001

  第1次:
    sum = 1111...1111 ^ 0000...0001 = 1111...1110
    carry = (1111...1111 & 0000...0001) << 1
          = 0000...0001 << 1
          = 0000...0010

  第2次:
    sum = 1111...1110 ^ 0000...0010 = 1111...1100
    carry = (1111...1110 & 0000...0010) << 1
          = 0000...0010 << 1
          = 0000...0100

  ...(继续直到carry=0)

  最终结果: 0000...0000 (0)

经典题目

LeetCode 问题

  • 两整数之和 - LeetCode 371
  • 两数相减 - 使用加法实现减法
  • 两数相乘 - 使用加法实现乘法
  • 两数相除 - 使用减法实现除法

扩展问题

  • 不使用乘除法实现乘法
  • 位运算实现减法、乘法、除法

⚖️ 优缺点

优点

  • ✅ 底层实现:理解计算机底层加法原理
  • ✅ 无需运算符:满足特殊限制
  • ✅ 性能好:位运算速度快

缺点

  • ❌ 可读性差:不如直接使用+
  • ❌ 负数复杂:需要特殊处理
  • ❌ 溢出风险:需要小心处理

🎨 应用场景

💡 优化技巧

💡 为什么使用 XOR 和 AND?

数学证明:
二进制加法规则:
  0 + 0 = 0 (和=0, 进位=0)
  0 + 1 = 1 (和=1, 进位=0)
  1 + 0 = 1 (和=1, 进位=0)
  1 + 1 = 10 (和=0, 进位=1)

观察:
- 和的规律: 相同为0,不同为1 → XOR
- 进位的规律: 都为1时产生 → AND

验证:
  A | B | A^B | A&B | (A&B)<<1
  --|---|-----|-----|----------
  0 | 0 |  0  |  0  |    0
  0 | 1 |  1  |  0  |    0
  1 | 0 |  1  |  0  |    0
  1 | 1 |  0  |  1  |    10

完全符合二进制加法规则!

相关主题


返回:位运算 | 算法学习导航