[每日一題] 第六題:不用加減乘除做加法

DRose發表於2020-07-31

寫一個函式,求兩個整數之和,要求在函式體內不得使用 “+”、“-”、“*”、“/” 四則運算子號。

示例:

輸入: a = 1, b = 1
輸出: 2

提示:

a, b 均可能是負數或 0
結果不會溢位 32 位整數

方法一:位運算

解題思路

本題考查對位運算的靈活使用,即使用位運算實現加法。

設兩數字的二進位制形式 a,b,其求和 s = a + b,a(i) 代表 a 的二進位制第 i 位,則分為以下四種情況:

a(i) b(i) 無進位和 n(i) 進位 c(i+1)
0 0 0 0
0 1 1 0
1 0 1 0
1 1 0 1

觀察發現,無進位和異或運算 規律相同,進位與運算 規律相同(並需左移一位)。因此,無進位和 n 與進位 c 的計算公式如下:

n = a ⊕ b 非進位和:異或運算
c = a & b << 1 進位:與運算 + 左移一位

(和 s)= (非進位和 n) + (進位 c)。即可將 s = a + b 轉化為:s = a + b => s = n + c

迴圈求 n 和 c,直至進位 c = 0;此時 s = n,返回 n 即可。

[每日一題] 第六題:不用加減乘除做加法

Q : 若數字 aa 和 bb 中有負數,則變成了減法,如何處理?

A : 在計算機系統中,數值一律用 補碼 來表示和儲存。補碼的優勢: 加法、減法可以統一處理(CPU只有加法器)。因此,以上方法 同時適用於正數和負數的加法 。

程式碼

class Solution {
    public int add(int a, int b) {
        while(b != 0) { // 當進位為 0 時跳出
            int c = (a & b) << 1;  // c = 進位
            a ^= b; // a = 非進位和
            b = c; // b = 進位
        }
        return a;
    }
}

複雜度分析

時間複雜度O(1) :最差情況下(例如 a = 0x7fffffff,b = 1 時),需迴圈 32 次,使用 O(1) 時間;每輪中的常數次位操作使用 O(1) 時間。

空間複雜度O(1) :使用常數大小的額外空間。

個人理解

以 9 + 7 為例,詳細手動模擬一下步驟:

十進位制模擬

第一次迴圈,計算 9 + 7:

無進位和:9 + 7 = 6。

進位:個位進一位為 1,進到十位了,所以要 * 10,即 10。

第二次迴圈,計算 6 + 10:

無進位和

個位:0 + 6 = 6

十位:1 + 0 = 1

結果為 16

進位:個位無進位,十位無進位,

所以最終結果為 16。

二進位制模擬

9 的二進位制為:1001

7 的二進位制位:111

第一次迴圈,計算 1001 + 111:

無進位和(異或):1001 ^ 111 = 1110

進位(與):1001 & 111 = 1

十進位制進位就應該 x10,二進位制進位就得左移一位,所以 1 << 1 = 10

第二次迴圈,計算 1110 + 10:

無進位和(異或):1110 ^ 10 = 1100

進位(與):1110 & 10 << 1 = 10 < < 1 = 100

第三次迴圈,計算 1100 + 100:

無進位和(異或):1100 ^ 100 = 1000

進位(與):1100 & 100 << 1 = 100 < < 1 = 1000

第四次迴圈,計算 1000 + 1000:

無進位和(異或):1000 ^ 1000 = 0000

進位(與):1000 & 1000 << 1 = 1000 < < 1 = 10000

第五次迴圈,計算 0000 + 10000:

無進位和(異或):0000 ^ 10000 = 10000

進位(與):0000 & 10000 << 1 = 00000 < < 1 = 000000

這個時候就該結束了,因為此時無進位了。

此時 10000 的值就是最終結果,換成十進位制為 16。

為什麼十進位制相加迴圈次數這麼少?而二進位制迴圈次數這麼多呢? 因為二進位制位數多,碰到特別情況,比如該情況,一位一位向上進,所以迴圈次數就多了。

那麼什麼時候結束迴圈呢? 就是沒有進位的時候,不需要再加了。

為什麼要有迴圈呢? 因為相加就會產生進位,進位了說明沒算完,需要繼續加上進位,知道沒有進位。

題解來源

作者:jyd

連結:leetcode-cn.com/problems/bu-yong-j...

來源:力扣(LeetCode)

方法二:奇思妙想解法

程式碼

真沒有運算子!!

class Solution:
    def add(self, a: int, b: int) -> int:
        result = [a,b]
        return sum(result)

題解來源

作者:luyao777

連結:leetcode-cn.com/problems/bu-yong-j...

來源:力扣(LeetCode)

來源:力扣(LeetCode)

連結:leetcode-cn.com/problems/bu-yong-j...

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章