题目描述
给你两个二进制字符,返回它们的和(用二进制表示)。
输入为非空 字符串,且只包含数字1
和 0
。
示例1:
输入: a = “11”, b = “1”
输出: “100”
示例2:
输入: a = “1010”, b = “1011”
输出: “10101”
提示:
- 每个字符串仅由字符
0
或1
组成; 1 <= a.length, b.lenght <= 10E4
;- 字符串如果不是
"0"
, 就都不含前导零。
思路分析
难度是简单 , 这道题特点是乍一看比较简单,但是实现起来容易出现一些无法简化的地方,如一开始笔者想要减少计算量,所以采取多余部分单独切除,相等长度部分带进位相加的思路,但是在实现过程中发现如果多部分为111
,相等部分相加后进位carry = 1
,则无法进一步简化,而是回到原始操作处,所以这里采用了短缺部分补0,补全后两个等长字符串带进位相加的方法。
所以这里实现思想只分两部分:
- 短缺部分补
'0'
; - 等长字符串带进位相加;
对于 步骤1,我们需要获取两个字符串的长度,这里我们假设为lenA, lenB
,根据长度差得到应该补充的’0’的个数,之后再进行字符拼接操作。
这里我们将结果使用StringBuilder
进行存储,在步骤1中我们借助其存储'0'
字符串,且在进行拼接后,需要清除数据;
代码1: 字符补‘0’
StringBuilder res = new StringBuilder();
int lenA = a.length();
int lenB = b.length();
/* STEP1: fill '0' on the left if they two has unsame length
*/
if (lenA != lenB) {
int delta = lenA - lenB;
for (int i = 0; i < Math.abs(delta); i++)
res.append('0');
if (lenA > lenB)
b = res.append(b).toString();
else
a = res.append(a).toString();
lenA = Math.max(a.length(), b.length());
// clear res
res.delete(0, res.length());
}
在对两字符串等长操作后,我们直接进行相加,即步骤2,等长相加,这里我们进一步利用二进制的特性,不进行位操作,这里我们给出所有的情况:
表1 进位carry
为0时
charA | charB | carry(prev) | curr | carry(curr) |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 0 |
1 | 0 | 0 | 1 | 0 |
1 | 1 | 0 | 0 | 1 |
表1 进位carry
为1时
charA | charB | carry(prev) | curr | carry(curr) |
---|---|---|---|---|
0 | 0 | 1 | 1 | 0 |
0 | 1 | 1 | 0 | 1 |
1 | 0 | 1 | 0 | 1 |
1 | 1 | 1 | 1 | 1 |
我们不难发现,当charA == charB
时,curr = carry(prev), carry(curr) = charA
; 当charA != charB
时,carry(curr) = carry(prev)
,carry
即不变,curr
为carry(prev)
取非(即0->1; 1->0
);需要注意的是,在返回res
之前,需要判断carry == '0'?
,之后将res
反转并转化为字符串后输出。
这里直接给出代码有:
代码2:等长字符串相加
Character carry = '0';
for (int i = lenA - 1; i >= 0; i--) {
if (a.charAt(i) == b.charAt(i)) {
res.append(carry);
carry = a.charAt(i);
} else
res.append(carry == '0' ? '1' : '0');
}
res.append(carry == '0' ? "" : carry);
解题代码
public static String solution(String a, String b) {
StringBuilder res = new StringBuilder();
int lenA = a.length();
int lenB = b.length();
/* STEP1: fill '0' on the left if they two has unsame length
*/
if (lenA != lenB) {
int delta = lenA - lenB;
for (int i = 0; i < Math.abs(delta); i++)
res.append('0');
if (lenA > lenB)
b = res.append(b).toString();
else
a = res.append(a).toString();
lenA = Math.max(a.length(), b.length());
res.delete(0, res.length());
}
/* STEP2: add bit by bit
*/
Character carry = '0';
for (int i = lenA - 1; i >= 0; i--) {
if (a.charAt(i) == b.charAt(i)) {
res.append(carry);
carry = a.charAt(i);
} else {
res.append(carry == '0' ? '1' : '0');
}
}
res.append(carry == '0' ? "" : carry);
return res.reverse().toString();
}
复杂度分析
这里我们设m,n
为输入字符串长度;
时间复杂度: 这里步骤1需要abs(m-n)
次补'0'
操作;步骤2需要访问O(max(m,n))
次字符,故为O(abs(m-n) + max(m,n))
,取两项较大值,则有时间复杂度为O(max(m,n))
;
空间复杂度: 这里res
为返回容器,且随输入字符的长度变化为变化,则空间复杂度为O(max(m,n))
;
Github源码
完整可运行文件请访问GitHub。