題目:
Given a range [m, n]where 0 <= m <= n <= 2147483647, return the bitwise AND of all numbersin this range, inclusive.
For example, giventhe range [5, 7], you should return 4.
分析:
這道題要求計算一定範圍內所有整數的按位與,常規方法,可以對於該範圍內的所有整數依次進行按位與操作,但這種方法的時間複雜度爲O(N)。通過對數據進行分析,其實我們可以使用更省時的方法。
(1)首先,先看個簡單例子:
Fig.1
Fig.1呈現的是0~8的二進制表示,我們可以發現:
從右到左第0位的0和1交替出現,也就是說對於任意2個或2個以上的連續整數,這一位必然會同時出現0和1,而要出現0->1->0或者1->0->0的情況,至少得要3個連續整數。
從右到左第1位的0 和1每隔2個數交替出現,也就是說對於任意大於等於3個的連續整數,這一位必然會同時出現0和1,而要出現0->1->0或者1->0->0的情況,至少得要4個連續整數。
從右到左第2位的0 和1每隔4個數交替出現,也就是說對於任意大於等於5個的連續整數,這一位必然會同時出現0和1,而要出現0->1->0或者1->0->0的情況,至少得要6個連續整數。
……
按照這個規律,我們可以總結出:
a:對於任意大於等於2^n+1個的連續整數,從右到左的第0~n位,每一位必然會同時出現0和1。
b:對於第n位,如果要出現0->1->0或者1->0->0的情況,至少得要2^n+2個連續整數才行。
(2)其次,對於按位與,只有當某一位的值全部爲1,它的計算結果纔可能爲1,(1&1=1、1&0=0、0&0=0)。
(3)最後,要對範圍[m,n]內的所有整數進行按位與運算,那麼,根據(2),我們可以得出,對於從右到左的第x位,除非[m,n]範圍內的所有整數的第x位值都爲1,最終的結果result的第x位值纔可能爲1。
由(1)a可知,對於大於等於(2^x+1)個的連續整數,從右到左的第0~x位,每一位必然會同時出現0和1,也就是說reslut的第0~x位必然爲0。
而[m,n]共包含了len=n-m+1個連續整數,所以,只需要求解出最大的那個x值,即滿足Eq.1,便可以確定後reslut的第0~x位的值。
2^(x+1)+1>len>=2^x+1 (1)
此外,對於[m,n]範圍中的連續整數,對於前面的任意一位y(y>x),只可能出現0->1、1->0、0->0、1->1的情況。(爲什麼呢?反證:假設出現了0->1->0或者1->0->0的情況,由(1)b可知,len>=2^y+2,而y>x,這和Eq.1相矛盾。)所有,我們要想確定前面每一位的result值,只需要對m和n進行&運算即可。
綜上,本題的解決方法爲:
-
計算len,(len= n-m+1);
-
計算x使得2^(x+1)+1>len>=2^x+1;
-
計算m&n;
-
計算result,其二進制值爲m&n並將後x位賦值爲0。
(畫外音:在腦袋裏想的時候感覺挺簡單的,可用文字卻發現怎麼也描述不清楚……是我的語言組織能力太爛了嗎??囉嗦了一大堆,也不知道說清楚了沒……=_=b)
代碼:
<span style="font-size:14px;"><span style="font-family:System;font-size:14px;">class Solution {
public:
int rangeBitwiseAnd(int m, int n) {
if(m<0||n>2147483647)
return 0;
if(n<m)
return 0;
int len=n-m+1-1;
int bSize_len=-1;
while(len!=0)
{
len=len/2;
bSize_len++;
};
int result=m&n;
for(int i=0;i<=bSize_len;i++)
result&=~(1<<i);
return result;
}
};
</span></span>
總結:
1、位移動操作符<<、>>爲什麼會失效?
最初,我使用如下代碼計算result:
<span style="font-size:14px;"><span style="font-family:System;font-size:14px;">n>> bSize_len;
m>> bSize_len;
int result=m&n;
result<< bSize_len;
</span></span>
但調試發現,右移運算符卻沒有被執行?