LeetCode 67. 二进制求和
题目描述
给你两个二进制字符串 a 和 b,以二进制字符串的形式返回它们的和。
示例 1:
输入: a = "11", b = "1"
输出: "100"
示例 2:
输入: a = "1010", b = "1011"
输出: "10101"
解题思路
二进制加法与十进制加法类似,从低位到高位逐位相加并处理进位。区别在于二进制是"逢二进一"。模拟竖式计算过程:
- 用指针
i和j分别指向字符串a和b的末尾(最低位)。 - 用变量
carry记录当前位的和及进位(初始为 0)。 - 当
i或j未越界,或仍有进位时循环:- 若
i未越界,将a[i]转换为数字加到carry,左移i。 - 若
j未越界,将b[j]转换为数字加到carry,左移j。 - 当前位结果为
carry % 2,转换为字符插入结果字符串。 - 更新进位
carry = carry / 2。
- 若
- 反转结果字符串得到正确顺序。
巧妙之处:
- 合并"当前位和"与"进位"为同一变量
carry。 - 循环条件覆盖所有情况(包括剩余进位)。
- 单循环处理两字符串剩余部分。
代码实现
cpp
class Solution {
public:
string addBinary(string a, string b) {
int i = a.size() - 1, j = b.size() - 1, carry = 0;
string res;
while (i >= 0 || j >= 0 || carry) {
if (i >= 0) carry += a[i--] - '0';
if (j >= 0) carry += b[j--] - '0';
res.push_back(carry % 2 + '0');
carry /= 2;
}
reverse(res.begin(), res.end());
return res;
}
};
复杂度分析
- 时间复杂度 :
O(max(m, n)),需遍历两字符串各一次。 - 空间复杂度 :
O(max(m, n)),存储结果字符串所需空间。
示例演示
以 a = "11", b = "1" 为例:
| 步骤 | i | j | carry(进入循环时) | 操作 | 新 carry | 当前位结果 |
|---|---|---|---|---|---|---|
| 初始化 | 1 | 0 | 0 | - | - | - |
| 第1次循环 | 1 | 0 | 0 | 加 a[1]=1 → carry=1 加 b[0]=1 → carry=2 |
2 | '0' |
| 进位更新 | - | - | - | carry=2/2=1 |
1 | - |
| 第2次循环 | 0 | -1 | 1 | 加 a[0]=1 → carry=2 j<0 不加 |
2 | '0' |
| 进位更新 | - | - | - | carry=2/2=1 |
1 | - |
| 第3次循环 | -1 | -1 | 1 | i<0 不加 j<0 不加 |
1 | '1' |
| 进位更新 | - | - | - | carry=1/2=0 |
0 | - |
结果字符串依次存入 '0', '0', '1',反转后为 "100"。
小结
本题是模拟竖式加法的经典问题。通过合并当前位和与进位,并利用循环条件简化代码。该思路可扩展至其他进制(如十进制、十六进制),仅需调整模数和除数。