算法修煉之路—【字符串】Leetcode 67 二進制求和

題目描述

給你兩個二進制字符,返回它們的和(用二進制表示)。

輸入爲非空 字符串,且只包含數字10

示例1:

輸入: a = “11”, b = “1”
輸出: “100”

示例2:

輸入: a = “1010”, b = “1011”
輸出: “10101”

提示:

  • 每個字符串僅由字符01組成;
  • 1 <= a.length, b.lenght <= 10E4;
  • 字符串如果不是"0", 就都不含前導零。

思路分析

難度是簡單 , 這道題特點是乍一看比較簡單,但是實現起來容易出現一些無法簡化的地方,如一開始筆者想要減少計算量,所以採取多餘部分單獨切除,相等長度部分帶進位相加的思路,但是在實現過程中發現如果多部分爲111,相等部分相加後進位carry = 1,則無法進一步簡化,而是回到原始操作處,所以這裏採用了短缺部分補0,補全後兩個等長字符串帶進位相加的方法。

所以這裏實現思想只分兩部分:

  1. 短缺部分補'0';
  2. 等長字符串帶進位相加;

對於 步驟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即不變,currcarry(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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章