位運算的妙用_判斷2的乘方和二進制1的個數

本來定好每個星期寫一遍算法的博客的,可是因為最近趕項目,博客停止更新一段時間了,現在抽空繼續更新。本來心情挺好的,一看手機,欠費兩百多,真是日了狗了,百度云沒有設置只能 wifi 下下載和上傳,用了我的流量來下載,我的內心是崩潰的。


扣費截圖

一、判斷一個整數是否是2的乘方

1.題目:實現一個方法,判斷一個正整數是否是2的乘方(比如 16 是 2 的 4 次方,返回 True;18 不是 2 的乘方,返回 False )。要求性能盡可能高。

解法一:
創建一個變量 Temp ,初始值是 1 。然后進入一個循環,循環中每次讓Temp和目標整數比較,如果相等,則說明目標整數是 2 的乘方;如果不相等,則讓 Temp 增大乘 2 ,繼續循環比較。當 Temp 大于目標整數時(所以循環的判斷條件是小于等于),說明目標整數不是 2 的乘方。

    /**
     * 判斷整數(number)是否是2的乘方
     * 
     * @param number
     * @return
     */
    public static boolean isPower2_ONE(int number) {
        int temp = 1;
        while (temp <= number) {
            if (temp == number) {
                return true;
            }
            temp = temp * 2;
        }
        return false;
    }

優化:
先了解一個知識點:<<(左移)乘二,>>(右移)除二

具體的介紹:

java的左移和右移不是循環移動,遵循下面的規則:

1.右移
右移運算用來將一個數的二進制位序列右移若干位。例如 x>>=2 ,使 x 的各二進制位右移兩位,移到右端的低位被舍棄,最高位則移入原來高位的值。例如:x=00110111,則 x>>2 為 00001101 ; y=11010011 ,則 y>>2 為11110100

2.左移
左移運算用來將一個數的二進制位序列左移若干位。例如 x<<=2 ,使 x 的各二進制位左移兩位,右邊補 0 ,若x=00001111,則x<<2為00111100.最高位左移后溢出,舍棄不起作用。

右移運算相當于對這個數字除2取商,左移運算相當于對這個數字乘2,而且使用左移右移實現乘法除法比使用乘法除法運算速度要快。

注意:以上等效是在不溢出的情況下進行。對于負數運算的左移是必然會溢出的

當然,如果要實現對負數的操作,由于計算機在處理負數的時候是對補碼進行操作,所以除2其實是對補碼的操作,因此對負數的操作需要對補碼進行處理。

注意:補碼運算的時候,最與最高位符號位是要保持不變的。另外,如果左移右移大于數據類型長度時候,會先取模。比如 int i ,左移 33 ,會變為左移 1 ,也就是 33%32

因此我們可以把上面循環中的乘 2 ,換成左移一位,因為左移運算符會比乘法的效率快很多。

    /**
     * 判斷整數(number)是否是2的乘方(把乘2換成左移一位)
     * 
     * @param number
     * @return
     */
    public static boolean isPower2_TWO(int number) {
        int temp = 1;
        while (temp <= number) {
            if (temp == number) {
                return true;
            }
            temp = temp << 1;
        }
        return false;
    }

雖然換成左移運算法效率會變快,可是時間復雜度還是沒有變化的,也就是說本質還是沒有改變。

解法二:
觀察下面的圖,我們可以發現什么規律呢?

十進制轉二進制

通過觀察我們可以發現:
(1) 凡是2的乘方的正整數,其二進制數必然是以 1 為首位,其它位都是 0
(2) 如果給它減 1 ,(在位數相同的情況下)就會變成首位是 0 ,其它位全部是 1 的結果
(3) 0 和 1 的按位與運算結果是 0 ,因此 2 的乘方和他本身減1相與,即 N & N-1,結果必然是 0;也就是說用“位與”運算,得到的結果是0,就說明這個正整數是2的乘方

所以,2 的乘方都符合一個規律,即 N&N-1 等于 0,所以直接用這個規律判斷即可,但是,這個結論就一定正確嗎?這只是我們通過觀察部分數據得出的結果,況且我們的數據量非常的少,怎樣才能保證這個結論是正確的呢?我們可以通過反證法來證明:

假設真的存在一個正整數 N,N 不是 2 的冪,但是 N 符合 N&N-1 =0。

由 N 不是 2 的冪可以推斷出,N 的二進制形式并不是除了最高位是1以外,其余為全是 0 。

既然其余位不全是 0 ,那么 N-1 的結果的最高位一定不會改變,仍然是1。

既然 N-1 的最高位是 1 ,N的最高位也是 1 ,那么 N&N-1!=0,和假設矛盾。

由此證明,符合 N&N-1 =0 的正整數必然是 2 的冪。

最后我們用代碼來實現:

    /**
     * 判斷整數(number)是否是2的乘方(位與運算)
     * 
     * @param number
     * @return
     */
    public static boolean isPower2_THREE(int number) {
        return (number & number - 1) == 0;
    }

二、求出一個正整數轉換成二進制后的數字“1”的個數

題目:求出一個正整數轉換成二進制后的數字“1”的個數
如:
int 型數值為 80
轉化成二進制形式:80 = 00000000 00000000 00000000 01010000
因此 1 的個數為 2

解法一:
由上面的位運算判斷 2 的乘方可以知道,n&(n-1) 可以把整數二進制的最右邊的數由 1 變為 0 ,利用這個我們就可以解決這個問題了。

具體實現的代碼如下:

    /**
     * 計算一個int型數值中bit-1的個數
     * 
     * @param n
     * @return
     */
    public static int bitCount1(int n) {
        int count = 0;
        while (n != 0) {
            n = n & (n - 1);
            count++;
        }
        return count;
    }

解法二:

我們也可以通過移位來解決這題,因為整數的二進制與 1 進行 & 運算的時候,當最末位也就是最右邊的一位為 1 的時候,結果就是 1 ,判斷完最后一位,然后把整數的二進制右移一位,再判斷,直到整數等于 0 結束循環


    /**
     * 計算一個int型數值中bit-1的個數
     * 
     * @param n
     * @return
     */
    public static int bitCount2(int n) {
        int count = 0;
        while (n > 0) {
            if ((n & 1) == 1) {// 如果最右邊的值是1
                count++;
            }
            n >>= 1; // 向右一位
        }
        return count;
    }

可是這種做法不是太好,因為 Java 中 int 占 4 個字節,一共 32 位,那么就是說,要循環 32 次才能結束

解法三:

其實這個題目在 Java ,Integer 類中 bitCount 方法的已經解決了的,我們可以看下大神們是如何巧妙的解決的。

Jdk中Integer的bitCount源碼

一開始沒想明白怎么推出來的,最后上網查了一下,

推斷1
推斷2

歡迎轉載,轉載請標明來源:

CSDN主頁:http://blog.csdn.net/two_water
簡書主頁:http://www.lxweimin.com/users/8ec863a03f4f/latest_articles


最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,923評論 6 535
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,740評論 3 420
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,856評論 0 380
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,175評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,931評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,321評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,383評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,533評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,082評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,891評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,067評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,618評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,319評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,732評論 0 27
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,987評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,794評論 3 394
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,076評論 2 375

推薦閱讀更多精彩內容

  • 位運算 位運算的運算分量只能是整型或字符型數據,位運算把運算對象看作是由二進位組成的位串信息,按位完成指定的運算,...
    IIronMan閱讀 7,882評論 0 2
  • 高級運算符(Advanced Operators) 本文參考自蘋果官方文檔Advanced Operators本頁...
    果啤閱讀 1,606評論 1 5
  • 高級運算符 文檔地址 作為 基本運算符 的補充,Swift 提供了幾個高級運算符執行對數傳值進行更加復雜的操作。這...
    hrscy閱讀 854評論 0 2
  • 當看到“手繪”、“彭小六”這些字眼的時候你會不馬上眼前一亮呢?反正我是立即就被吸引了。 今天看到小六的...
    云黛閱讀 581評論 5 4
  • 本節課的課題是影響化學反應速率的因素。教師圍繞溫度、濃度、催化劑三個方面探討展開探討,采用了教師主導學生主體,合作...
    裝蝴蝶朱閱讀 97評論 0 0