一、题目描述
给你两个二进制字符串 a 和 b ,以二进制字符串的形式返回它们的和。
示例 1
输入: a = "11", b = "1"
输出: "100"
示例 2
输入: a = "1010", b = "1011"
输出: "10101"
提示
1 <= a.length, b.length <= 10^4
a 和 b 仅由字符 '0' 或 '1' 组成
字符串如果不是 "0" ,就不含前导零
二、解题思路
这道题本质上是 二进制的大整数加法问题。
思路与我们手算加法完全一样:
1️⃣ 从 字符串末尾(最低位)开始相加
2️⃣ 使用一个变量 carry 记录 进位
3️⃣ 每一位的计算规则
sum = a位 + b位 + carry
当前位 = sum % 2
新的进位 = sum / 2
4️⃣ 因为是 从右往左计算 ,所以得到的字符串是 逆序的 ,最后需要 反转
举例说明
a = "1010"
b = "1011"
从右往左计算:
| a | b | carry | sum | 当前位 |
|---|---|---|---|---|
| 0 | 1 | 0 | 1 | 1 |
| 1 | 1 | 0 | 2 | 0 carry=1 |
| 0 | 0 | 1 | 1 | 1 |
| 1 | 1 | 0 | 2 | 0 carry=1 |
| 1 | 1 | 1 |
最终结果:
10101
三、代码实现(C语言)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* addBinary(char* a, char* b) {
int lenA = strlen(a);
int lenB = strlen(b);
int maxLen = lenA > lenB ? lenA : lenB;
// 最多多一位进位
char* res = (char*)malloc((maxLen + 2) * sizeof(char));
int i = lenA - 1;
int j = lenB - 1;
int k = 0;
int carry = 0;
while (i >= 0 || j >= 0 || carry) {
int sum = carry;
if (i >= 0) sum += a[i--] - '0';
if (j >= 0) sum += b[j--] - '0';
res[k++] = (sum % 2) + '0';
carry = sum / 2;
}
res[k] = '\0';
// 反转字符串
for (int l = 0, r = k - 1; l < r; l++, r--) {
char temp = res[l];
res[l] = res[r];
res[r] = temp;
}
return res;
}
四、复杂度分析
时间复杂度
O(n)
其中 n = max(len(a), len(b))
每个字符最多遍历一次。
空间复杂度
O(n)
用于存储结果字符串。
五、优化思路(面试加分点)
实际上我们可以 直接从结果数组末尾填充 ,这样就 不需要反转字符串。
核心思想:
从后往前填充结果数组
这样代码会更加优雅。
六、总结
这道题的本质是 模拟二进制加法:
核心步骤:
1 从右往左遍历
2 计算 sum = a + b + carry
3 当前位 = sum % 2
4 更新进位 carry = sum / 2
5 最后反转字符串
掌握这种 字符串模拟加法思想,还可以解决很多类似问题:
-
LeetCode 415 字符串相加
-
LeetCode 989 数组形式的整数加法
-
大整数加法问题