按位反轉的求解

題目來源:

點擊打開鏈接

題目描述:

Given a positive integer, output its complement number. The complement strategy is to flip the bits of its binary representation.

Note:

  1. The given integer is guaranteed to fit within the range of a 32-bit signed integer.
  2. You could assume no leading zero bit in the integer’s binary representation.

Example 1:

Input: 5
Output: 2
Explanation: The binary representation of 5 is 101 (no leading zero bits), and its complement is 010. So you need to output 2.

Example 2:

Input: 1
Output: 0
Explanation: The binary representation of 1 is 1 (no leading zero bits), and its complement is 0. So you need to output 0.


我的解決方案:

class Solution {
public:
    int findComplement(int num) {
        int ret=0,tmp[32]={},size=0;
        while(num>0)
        {
            tmp[size]=(num%2==0?1:0);
            size++;
            num/=2;
        }
        for(int i=size-1;i>=0;--i)
            ret=ret*2+tmp[i];
        return ret;
    }
};

思考:

這是一個按比特位進行反轉的問題,思路上來說用按位與和按位或來解決應該是最快的方式,但是做的時候對這部分的概念有點模糊,所以採取了比較簡單粗暴的笨辦法來解決,先轉換成二進制表示,由於題目內給定了大小,所以一個32位的數組作爲棧可以存下這個正整數二進制的位,在存入棧的同時就可以進行反轉,由於題目的限制,反轉之後首位必然爲0,所以從size-1開始反向遍歷,由二進制計算回十進制就得到了答案.這個方法很淺顯很好想,但是效率不夠,既需要一個棧空間的內存,又需要進行兩次循環,時間和空間都比較低效.所以我在leetcode上完成ac之後,又點進了討論區查看別的大神們的答案,下面是個摘錄:(在此對lzl124631x137作者表示感謝)

 class Solution {
public:
    int findComplement(int num) {
        unsigned mask = ~0;
        while (num & mask) mask <<= 1;
        return ~mask & ~num;
    }
};
For example,

num          = 00000101
mask         = 11111000
~mask & ~num = 00000010

這種算法的思路就更爲清晰簡潔了,先假設num一共N位有效位,要求num的反轉,則直接將num的二進制整個反轉(~num).則去掉前32-N位的1(很明顯num的前32-N位必然是0),只保留後N位有效位即可.所以現在只需要獲取一個前32-N位爲0,後N位爲1的數,然後與~num進行按位與計算就好了.要得到這種數很明顯應該對0或者0xFFFFFFFFF進行移位操作,知道num的有效位數就知道需要移動多少位了.所以,先定義了無符號數mark,作爲0的反轉,則二進制爲全1,即0xFFFFFFFF,while(num & mark)這個循環條件決定了,num二進制上有多少個有效位就能循環多少次(當然這是以循環體裏面每次對mark左移1位爲條件的),則循環結束之後,mark的前32-N位都是1,後N位都是0,mask的反轉則是我們所需要的二進制形式,再按位與一次,則得到結果.

這種算法的關鍵在於這個while循環,&操作只要有二進制位,則結果位true,通過將0xFFFFFFFF不停移位,則可以知道num的有效位數

此外,補充一下整數移位的規則:

點擊打開鏈接

簡單來說,無符號數的左移右移都是補0,有符號數的左移是補0,右移是補符號位

發佈了31 篇原創文章 · 獲贊 6 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章