題目描述
給你兩個二進制字符,返回它們的和(用二進制表示)。
輸入爲非空 字符串,且只包含數字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。