今天刷Leecode刷到第371題:
Calculate the sum of two integers a and b, but you are not allowed to use the operator + and -.
Example:
Given a = 1 and b = 2, return 3.
Credits:
Special thanks to @fujiaozhu for adding this problem and creating all test cases.
Subscribe to see which companies asked this question
題目要求我們在不使用加減操作符的情況下得到兩個整數的和。由於減法和乘除法都是基於加法操作的,所以此題不能考慮‘+’、‘-’、‘*’、’/‘
這四個操作符,我們使用位運算來得到兩個數的和。
假設a = 15, b = 9
, 先把a,b轉化為二進位制,那麼a = 1111,b = 1001
,二進位制的加法是逢2進1,如果兩個數的同一位的基數分別是0和1,那麼這個位上的基數為1;如果都是1,則基數為0;如果都是0,則基數為0。這種方式類似於位運算中的異或,只有兩個數字不等的時候結果才為1,那我們是不是可以直接用a ^ b
來得到a + b
的值呢?當然不行,當同一位上兩個基數都為1時,此時該位上的基數變為0,但是應該在它的左邊一位加1,異或運算並沒有給它加1,所以我們還得把逢2進1的那個1加進去,01 + 01 = 10
,所以兩個數有一個位上的基數都是1的時候相加就類似於與運算,但是要把結果左移一位,因為它是在比它高一位的地方進1,相當於是乘以2了。於是兩個二進位制的加法就轉化成了兩部分,一部分是兩個數同一位上的基數同為1的值,這部分的值用(a & b)<<1
可以得到,另一部分的值可以用異或得到,即 a ^ b
,所以 a + b = a ^ b + (a & b)<<1
.
在上一例中,
(a & b)<<1 = (1111 & 1001)<<1 = 10010;
a ^ b = 1111 ^ 1001 = 110;
a + b = 10010 + 110 = 11000 = 24
完整的程式碼如下:
var getSum = function(a, b) {
//注意'+'的優先順序大於'<<',所以要先把(a & b)<<1括起來
var s = (a ^ b) + ((a & b)<<1)
return s
};
異或還有一個特點就是,一個整數與0異或的結果就等於它自己,它和自己異或等於0,這個結論能幫我們解決第136題。
[Single Number][2]
Given an array of integers, every element appears twice except for one. Find that single one.
Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
Subscribe to see which companies asked this question
要找出一個陣列裡唯一的那個數,這時候我們很自然就想到了異或的特點,即:
a ^ 0 = a
a ^ a = 0
a ^ b ^ a = a ^ a ^ b = 0 ^ b = b
所以這道題我們利用for迴圈將陣列裡的所有元素異或,最終得到的就是那個只出現了一次的數,程式碼如下:
var singleNumber = function(nums) {
var result = 0
for(var i = 0; i < nums.length; i++) {
result = result ^ nums[i]
}
return result
};
可見有時候位運算的作用也很大呢!