用 O(1) 時間檢測整數 n 是否是 2 的冪次。
樣例
n=4,返回 true;
n=5,返回 false.
除以2
這個當然是很簡單也最容易想到,int的話可能要除31次才能出來。
統計1的位數
這個也容易想到,如果是2的冪次的話肯定是正的,然后去統計1的個數,需要移位和取且操作,和上面的方法差不多。因為除2本來就可以通過移位操作完成。
bool checkPowerOf2(int n) {
int num=0;
for(int i=0;i<31;i++)
{
if((n>>i)&1==1)
{
num++;
}
}
return num==1;
// write your code here
}
n和n-1取且
這個是以前檢測有多少個1的時候用到的一種方法,那個時候有一個結論:n&n-1可以減少一位1,如果用這種方法,那代碼是相當簡單:也符合時間復雜度要求。
bool checkPowerOf2(int n) {
if(n<=0)
return false;
return !(n&(n-1));
// write your code here
}
還有復習一下計算機中數字的表達形式:
- 有符號數最高位做符號位,0為正,1為負。
- 正數就是按照正常的表示方法。
- 負數用補碼表示,補碼為反碼加1,反碼是除符號位外其他位逐位取反。
- -0表示當前位數最小的那個數。
- n位有符號數的表示范圍: -2^n-- 2^(n-1)-1
原碼的表示:
左邊是符號位,正數為0,負數為1。其他位表示數值
【+10】原碼 = 00001010
【-10】原碼 = 10001010
【+0】原碼 = 00000000
【-0】原碼 = 10000000
反碼的表示:
正數的反碼和原碼相同,負數的反碼由原碼除了符號位的其余位取反(即0表1,1表0)
【+10】反碼 = 00001010
【-10】反碼 = 11110101
【+0】反碼 = 00000000
【-0】反碼 = 11111111
補碼的表示:
正數的補碼與原碼相同,負數的補碼由原碼的反碼加1得到
【+10】補碼 = 00001010
【-10】補碼 = 【-10】反碼 + 1 = 11110101 + 1 = 11110110
【+0】補碼 = 00000000
【-0】補碼 = 【-0】反碼 + 1 = 11111111 + 1 = 【1】00000000(mod(256))
補碼的意義:補碼實際上是一種模運算,以時鐘為例,時鐘一圈是12個小時,即時鐘的模為12。如果當前時刻是3點鐘,在12個小時之后時刻變為15點,15在模12之后,依然是3點。再如,將3點的時針調慢一個小時,即調成2點,和將時針向前調整11個小時的效果是一樣的。因此用3-1和(3+11)mod(12)的結果一樣。補碼在機器碼中的運用主要是用加法元算代替減法運算。CPU的加法器簡單效率高,因此不需要再專門實現減法器。
在8位字中,我們的模就是2的8次方,即256。例如:
直接減法:01000000(64)— 00001010(10) = 00110110(54)
用補碼代替減法:01000000(64)+(11110110)(246)= 00110110(54)
兩種運算結果是一樣的。