昨天LeetCode隨便找了一題準備日常開刷,題目是371.兩整數之和。題目大概要求是這樣的:不使用+和-的情況下,實現兩個整數的加法運算操作。有興趣請自行移步LeetCode查看這個題。
瞭解過計算機底層原理的應該知道,目前多數計算機是基於二進制,對十進制數字不能直接利用。即便是整體使用了二進制,但計算機利用其位操作確實實現了十進制的計算,所以算法上可以用類似的原理進行模擬實現這題的需求。原理核心主要是:異或負責表示該位運算結果,兩個數相與後左移一位負責表示進位。當進位出現0之後就停止運算,輸出這時異或的值。
開始沒想太多,python寫出來大概就4行左右,腳本運行後發現做運算的兩個數在同符號的情況下沒有問題,一旦兩個數字是異號的時候,程序就陷入了無限循環。
while b:
a, b = a ^ b, (a & b) << 1
return a
然後用打印輸出的方式查看,發現數字已經十分龐大,然而還在翻倍變化,沒有停下來。
隨後思考了一番,想到了python數字的特點,聲明的時候沒有類型的定義,小數和整數有時候運算比較模糊,重要的是一個整數超過表示範圍之後是可以變長的,變成大數運算,不會發生整數溢出。因爲這個特性,所以數字位數不斷增多,按照算法設計想要在最後異或出0是個難事。自動轉化這個現象很好驗證,int表示範圍內高次方或者大範圍階乘這樣的大數運算,可以看得出來這個特性。
既然數字都是按照補碼來的,可以通過與運算的方式人爲地製造溢出,捨棄過大的那一部分。拿64位的python來說,每次異或運算或者與運算之後再和0xFFFFFFFF做一次與運算,從而保證數據的長度。最後注意一下數的大小,如果結果大於0x7FFFFFFF,溢出了,還要和0xFFFFFFFF異或之後取反。
最後通過的代碼:
class Solution:
def getSum(self, a, b):
"""
:type a: int
:type b: int
:rtype: int
"""
while b:
a, b = (a ^ b) & 0xFFFFFFFF, ((a & b) << 1) & 0xFFFFFFFF
if a> 0x7FFFFFFF:
a = ~(a ^ 0xFFFFFFFF)
return a
位運算要慎重,位運算要慎重,位運算要慎重!