位運算面試題常用技巧
位運算是面試中的常見考題一種,位操作有~, <<, >>, &, |, ^六種。
左移和右移規則
對左移而言,移動正數和負數規則是相同的;對於右移而言,則有些差別,正數補0,負數補1。
舉例說明:
對於一個16位的整數:0000 0000 0000 0101,左移一位是0000 0000 0000 1010,右移一位是0000 0000 0000 0010
對於一個16位的負數:1000 0000 0000 0101,左移一位是0000 0000 0000 1010,右移一位是1100 0000 0000 0010
下面通過幾個典型的題目來透徹分析位運算的一些常用技巧。
技巧一:
對於正整數,左移一位,就是將數值乘2;右移一位就運算數值除2;但是位操作的效率要比運算子高。
技巧二:
一個數和另一個數異或兩次得到的還是原來的數
題:不用臨時變數交換兩個整數。
a = a ^ b;
b = a ^ b;
a = a ^ b;
技巧三:
n & (n - 1)將整數n的最後一位為1的位變成0
- 題:統計一個整數中二進位制位上1的個數。
int fun(int num)
{
int count = 0;
while(num)
{
num = num & (num - 1);
++count;
}
return count;
}
- 題:判斷一個數是不是2的冪。
//返回0表示是2的冪,返回非0值表示不是2的冪
int fun(int num)
{
return n & (n - 1);
}
解析:如果一個數是2的冪,則其有且只有一位為1。因此,消除這一位後就會變成0
- 題:判斷一個32位整數是不是4的冪
//返回0表示不是4的冪,返回非0表示是4的冪
int fun(int num)
{
if(!(n & (n - 1)))
{
return (n & 0x55555555);
}
return 0;
}
解析:是4的冪的數一定是2的冪,因此先判斷是不是2的冪,2的冪中1在基數位上的是4的冪,與0x55555555按位與,如果在基數位上有數則不為0
- 題:輸入兩個整數m和n,計算需要改變多少位能使m變成n
int fun(int m, int n)
{
//將m和n按位異或,相同的位為0,不同的位為1
m = m ^ n;
int count = 0;
//統計不同的位有多少個就ok
while(m)
{
m = m & (m - 1);
++count;
}
return count;
}
技巧四:
n & (~n + 1)提取出整數n最後一位為1的數
舉例:n = 01101,~n是將n按位取反就是10010,~n + 1 = 10011,最後,n & (~n + 1) = 00001
- 題:統計一個整數中二進位制位上1的個數。
int fun(int num)
{
int count = 0;
while(num)
{
n -= n & (~n + 1);
++count;
}
return count;
}
技巧五:
不使用+,-,*,/完成整數相加
int Add(int num1, int num2)
{
int sum, carry;
do{
//將兩個數異或,模擬加法中相加不進位的結果
sum = num1 ^ num2;
//只考慮進位的情況
carry = (num1 & num2) << 1;
num1 = sum;
num2 = carry;
}
while(num2 != 0); //將結果相加的過程就重複上述過程,直到進位為0
return sum;
}
舉例分析程式碼過程:
將12(二進位制表示為0000 1100)與5(二進位制表示為0000 0101)相加
第一次迴圈:
0000 1100 ^ 0000 0101 = 0000 1001
(0000 1100 & 0000 0101) << 1 = 0000 1000
第二次迴圈:
(0000 1001 ^ 0000 1000) = 0000 0001
(0000 1001 & 0000 1000) << 1 = 0001 0000
第三次迴圈:
(0000 0001 ^ 0001 0000) = 0001 0001
(0000 0001 & 0001 0000) << 1 = 0000 0000
迴圈結束
結果為0001 0001 = 17
僅以此文紀念2017年阿里內推失敗,校招繼續加油。