5.3 位运算专题:LeetCode 371. 两整数之和

发布于:2025-03-25 ⋅ 阅读:(35) ⋅ 点赞:(0)
1. 题目链接

LeetCode 371. 两整数之和


2. 题目描述

不使用运算符 +-,计算两个整数 ab 的和。
示例

  • 输入:a = 1, b = 2 → 输出:3
  • 输入:a = -1, b = 1 → 输出:0

3. 示例分析
  1. 正数相加
    • a = 3, b = 5 → 二进制 0011 + 0101 → 结果 1000(十进制 8)。
  2. 负数与正数相加
    • a = -1(二进制补码全 1),b = 1 → 结果 0
  3. 进位传递
    • a = 151111),b = 1 → 结果 1610000)。

4. 算法思路

核心思想位运算模拟加法器

  1. 无进位相加
    • 使用异或运算 a ^ b 得到无进位相加的结果。
    • 异或的特性:0+0=0, 1+1=0(无进位),1+0=1
  2. 计算进位
    • 使用与运算 a & b 找到需要进位的位,左移一位得到进位值。
  3. 循环处理进位
    • 将进位值与无进位和重复上述操作,直到进位为 0

数学原理

  • 加法可分为两部分:无进位和 x = a ^ b 和进位 carry = (a & b) << 1
  • 最终结果为 x + carry,但需要通过循环将进位合并到结果中。

5. 边界条件与注意事项
  1. 负数处理
    • 使用 unsigned int 转换进位,避免有符号数左移的未定义行为。
  2. 循环终止条件
    • 当进位 carry0 时,结束循环。
  3. 符号位兼容性
    • 补码表示下,该算法天然支持负数运算。

6. 代码实现
class Solution 
{
public:
    int getSum(int a, int b) 
    {
        while (b) 
        {
            int x = a ^ b;         // 无进位相加
            unsigned int carry = (unsigned int)(a & b) << 1; // 计算进位
            a = x;
            b = carry;
        }
        return a;
    }
};

在这里插入图片描述


与暴力枚举法的对比

方法 时间复杂度 空间复杂度 核心思想
位运算法 O(1) O(1) 模拟硬件加法器,逐位处理进位
暴力枚举法 O(n) O(1) 通过循环增/减 1 逐次逼近结果

位运算法的优势
  1. 时间复杂度最优:最多循环 32 次(32 位整数),时间复杂度为常数。
  2. 无额外空间:仅需临时变量存储中间结果。
  3. 支持负数运算:利用补码特性,天然兼容负数。

分步解析

  1. 初始状态
    • a = 30011),b = 50101)。
  2. 第一次迭代
    • x = 3 ^ 5 = 60110)。
    • carry = (3 & 5) << 1 = 1 << 1 = 20010)。
  3. 第二次迭代
    • x = 6 ^ 2 = 40100)。
    • carry = (6 & 2) << 1 = 2 << 1 = 40100)。
  4. 第三次迭代
    • x = 4 ^ 4 = 0
    • carry = (4 & 4) << 1 = 4 << 1 = 81000)。
  5. 第四次迭代
    • x = 0 ^ 8 = 8
    • carry = (0 & 8) << 1 = 0
  6. 终止循环:返回 a = 8

总结

位运算法的核心在于通过异或和与运算,逐层处理进位,最终合并结果。相较于暴力法(若允许使用 ++ 运算符),其时间复杂度从 O(n) 优化至 O(1),尤其适合大整数运算。该算法不仅是计算机底层加法器的实现原理,也是解决“禁止使用运算符”类问题的经典范式。

应用扩展

  • 实现减法:a - b = a + (-b),需先计算 -b 的补码(~b + 1)。
  • 判断溢出:通过检查进位是否影响符号位。

关键点

  • 理解补码和位运算的底层逻辑。
  • 循环终止条件与进位的正确处理。

网站公告

今日签到

点亮在社区的每一天
去签到