一篇文章搞懂面試中l(wèi)eetcode位操作算法題

  • Single Number落單的數(shù)
  • 落單的數(shù) IISingle Number II
  • Single Number III落單的數(shù) III
  • Number of 1 Bits
  • Counting Bits
  • Reverse Bits
  • Missing Number
  • Sum of Two Integers
  • Power of Two
  • Power of Four

本文將根據(jù)題目總結(jié)常用的位操作常用的解決算法問題的技巧
如讀者對基本的位操作概念還不熟悉先紫,可以先參考筆者的文章淺談程序設(shè)計(jì)中的位操作http://www.reibang.com/p/294fc6605bb1

Single Number落單的數(shù)

給出2*n + 1 個的數(shù)字桅狠,除其中一個數(shù)字之外其他每個數(shù)字均出現(xiàn)兩次拧簸,找到這個數(shù)字。

思路:
一個數(shù)字和自己進(jìn)行異或操作會是0沟突,由于異或操作滿足交換定律,一個數(shù)和0進(jìn)行異或操作還是本身。所以這道題目的思路就來了,將所有出現(xiàn)兩次的數(shù)異或就都變成了0槽片,最后剩的那個數(shù)和0異或就還是本身何缓。直接將數(shù)組所有數(shù)異或,就可以找出那個落單的數(shù)

public class Solution {
    public int singleNumber(int[] nums) {
        int res = 0;
        for(int i=0;i<nums.length;i++)
            res ^= nums[i];
        return res;
    }
}

落單的數(shù) IISingle Number II

給出3*n + 1 個的數(shù)字还栓,除其中一個數(shù)字之外其他每個數(shù)字均出現(xiàn)三次碌廓,找到這個數(shù)字。

思路:
java中int是32位的剩盒,所以我們利用一個32的數(shù)組谷婆,分別記錄每一位1的情況,如果出現(xiàn)三次就清0辽聊,最后留下來的就是那個只出現(xiàn)1次的數(shù)字在那一位上的情況纪挎,然后進(jìn)行移位復(fù)原

public class Solution {
    public int singleNumber(int[] A) {
        int[] bits = new int[32];
        
        int res = 0;
        
        for(int i=0;i<32;i++) {
            for(int j=0;j<A.length;j++) {
                bits[i] += (A[j]>>i) & 1;
            }
            
            res = res | ((bits[i]%3) << i);
        }
        
        return res;
    }
}

如果要找出現(xiàn)4次或者出現(xiàn)5次等的情況,只要%5就行了跟匆。

Single Number III落單的數(shù) III

給出2*n + 2個的數(shù)字异袄,除其中兩個數(shù)字之外其他每個數(shù)字均出現(xiàn)兩次,找到這兩個數(shù)字玛臂。

思路
如果能把這兩個不同的數(shù)字分開烤蜕,那么直接采取落單的數(shù)1的方法異或就可以了。
所以迹冤,我們先考慮將所有數(shù)異或讽营,最后得到的結(jié)果是兩個不同的數(shù)的異或結(jié)果,然后我們找到最后一位為1的位泡徙,為1代表這兩個數(shù)在這一位上是不同的橱鹏。然后用這個位與數(shù)組中每個數(shù)相與,就可以把數(shù)分成兩部分锋勺,一部分里有第一個不同的數(shù)蚀瘸,另一部分有第二個不同的數(shù),所以這個時候我們只要直接異或就可以得到結(jié)果了庶橱。

public class Solution {
    public int[] singleNumber(int[] A) {
        int xor = 0;
        
        for(int i=0;i<A.length;i++) {
            xor ^= A[i];
        }
        
        // a&(a-1)將最后為1的一位變成0
        
        int lastbit = xor - (xor & (xor -1)); //取出最后一個為1的位
        
        int group0 = 0, group1 = 0;
        
        for(int i=0;i<A.length;i++) {
            if((lastbit & A[i]) == 0)
                group0 ^= A[i];
            else
                group1 ^= A[i];
        }
        
        return new int[]{group0,group1};
    }
}

Number of 1 Bits

Write a function that takes an unsigned integer and returns the number of ’1' bits it has (also known as the Hamming weight).
For example, the 32-bit integer ’11' has binary representation 00000000000000000000000000001011
, so the function should return 3.

思路:
依次拿每一位與1進(jìn)行比較贮勃,統(tǒng)計(jì)1的個數(shù),然后邏輯右移苏章,不能用算數(shù)右移寂嘉,算數(shù)右移會在高位加一。

public class Solution {
    // you need to treat n as an unsigned value
    public int hammingWeight(int n) {
        int ones = 0;
        while(n!=0) {
            ones += (n & 1);
            n = n >>> 1;
        }
        return ones;
    }
}

還有一種方法枫绅,我們知道n&(n-1)會把n中最后為1的一位變成0泉孩。
所以我們調(diào)用n&(n-1),看看調(diào)幾次這個數(shù)會變成0,就說明有幾個1.

public class Solution {
    // you need to treat n as an unsigned value
    public int hammingWeight(int n) {
        int sum = 0;
        
        while(n != 0) {
            sum++;
            
            n = n & (n-1);
        }
        return sum;
    }
}

Counting Bits

Given a non negative integer number num. For every numbers i in the range 0 ≤ i ≤ num calculate the number of 1's in their binary representation and return them as an array.

Example:
For num = 5 you should return [0,1,1,2,1,2].

思路:
我們當(dāng)然可以利用上一題的方法并淋,直接每個數(shù)計(jì)算一次
但也發(fā)現(xiàn)是存在規(guī)律的

image.png
public class Solution {
    public int[] countBits(int num) {
        int[] res = new int[num+1];
        
        for(int i=1;i<=num;i++)
            res[i] = res[i>>1] + (i & 1);
        
        return res;
    }
}

Reverse Bits

Reverse bits of a given 32 bits unsigned integer.

For example, given input 43261596 (represented in binary as 00000010100101000001111010011100), return 964176192 (represented in binary as 00111001011110000010100101000000).

思路:
利用位操作寓搬,先交換相鄰的兩位,再交換的四位县耽,再交換相鄰的八位句喷。
舉個例子镣典;
我們交換12345678
可以先變成 21436587
再變成43218765
最后87654321,交換成功

對于32位也是如此的思路唾琼。
關(guān)鍵如何用位操作實(shí)現(xiàn)兄春,首先交換兩位的話,可以先分別取出前一位
x & (10101010101010101101010锡溯。赶舆。。祭饭。)
換成16進(jìn)制就是
x & (0xaaaaaaaa)取出前一位芜茵,因?yàn)橐c要有后一位交換,所以右移一位甜癞,因?yàn)橹皇菃渭兊慕粨Q夕晓,所以是邏輯右移
(x & 0xaaaaaaaa) >>> 1
然后對后一位也進(jìn)行相應(yīng)的操作,很容易得出
(x & 0x555555555) << 1
最后分別將前一位后一位合起來悠咱,使用或操作就可以了
所以蒸辆,第一次交換后
x = ((x & 0xaaaaaaaa) >>> 1) | ((x & 0x55555555) << 1);

然后進(jìn)行第二次交換:
取出前兩位
x & (1100110011001100......)也就是 x & 0xcccccccc.
后面的步驟都是一樣的思路
x = ((x & 0xcccccccc) >>> 2) | ((x & 0x33333333) << 2);

第三次交換
x = ((x & 0xf0f0f0f0) >>> 4) | ((x & 0x0f0f0f0f) << 4);

第四次交換
x = ((x & 0xff00ff00) >>> 8) | ((x & 0x00ff00ff) << 8);

第四次交換
x = ((x & 0xffff0000) >>> 16) | ((x & 0x0000ffff) << 16);
交換成功

代碼就是上面的交換的過程

public class Solution {
    // you need treat n as an unsigned value
    public int reverseBits(int x) {
        x = ((x & 0xaaaaaaaa) >>> 1) | ((x & 0x55555555) << 1);
        x = ((x & 0xcccccccc) >>> 2) | ((x & 0x33333333) << 2);
        x = ((x & 0xf0f0f0f0) >>> 4) | ((x & 0x0f0f0f0f) << 4);
        x = ((x & 0xff00ff00) >>> 8) | ((x & 0x00ff00ff) << 8);
        x = ((x & 0xffff0000) >>> 16) | ((x & 0x0000ffff) << 16);
        return x;
    }
}

Missing Number

給出一個包含 0 .. N 中 N 個數(shù)的序列,找出0 .. N 中沒有出現(xiàn)在序列中的那個數(shù)析既。

public class Solution {
    public int missingNumber(int[] nums) {
        int xor = 0, i = 0;
    for (i = 0; i < nums.length; i++) {
        xor = xor ^ i ^ nums[i];
    }

    return xor ^ i;
    }
}

Sum of Two Integers

位操作實(shí)現(xiàn)A+B的操作是常見的算法題躬贡。
lintcode上就有一道容易題是這樣。

class Solution {
    /*
     * param a: The first integer
     * param b: The second integer
     * return: The sum of a and b
     */
    public int aplusb(int a, int b) {
        // write your code here, try to do it without arithmetic operators.
        if(a==0)return b;  
        if(b==0)return a;  
        int x1 = a^b;  
        int x2 = (a&b)<<1;  
        return aplusb(x1,x2); 
    }
};

上述代碼就實(shí)現(xiàn)了不用+操作符眼坏,利用位操作實(shí)現(xiàn)兩個數(shù)的相加操作拂玻。
現(xiàn)在我們來講解位操作實(shí)現(xiàn)兩個數(shù)相加的原理
首先,十進(jìn)制中宰译,我們知道檐蚜,7+8,不進(jìn)位和是5沿侈,進(jìn)位是1闯第,然后我們可以根據(jù)不進(jìn)位和和進(jìn)位5+1*10算出最后的結(jié)果15。
類似二進(jìn)制也可以采取這種方法
比如
a = 3缀拭,b = 6
a : 0011
b : 0110
不進(jìn)位和: 0101 也就是5
進(jìn)位:0010 也就是2
所以a+b變成5 + (2<<1)
5    0101
2<<1   0100
不進(jìn)位和 0001 = 1
進(jìn)位 0100 = 4
因此 a + b就變成了1 + 4 << 1
然后有
1    0001
4<<1   1000
不進(jìn)位和 1001 = 9
進(jìn)位 0000 = 0
當(dāng)時進(jìn)位為0時咳短,不進(jìn)位和為9即a + b之和。

可以發(fā)現(xiàn)上述是一個遞歸的過程蛛淋,所以也就不難寫出代碼了咙好。求兩個數(shù)的不進(jìn)位和實(shí)際上就是將兩個數(shù)異或操作即可。

Power of Two

Given an integer, write a function to determine if it is a power of two.
要為2的次方
1褐荷,2勾效,4,8,16
也就是每位分別單獨(dú)為1
1
10
100
1000
10000
所以n & (n-1)必須為0

public class Solution {
    public boolean isPowerOfTwo(int n) {
        if(n<=0)
            return false;
        return (n & (n-1)) == 0;
    }
}

Power of Four

Given an integer (signed 32 bits), write a function to check whether it is a power of 4.
按照上一題的思路葵第,我們先列舉出幾個4的次方數(shù)绘迁,觀察他門的規(guī)律
1
100
10000
1000000
我們發(fā)現(xiàn)不僅要2的次方的性質(zhì),還要滿足 1所在的位必須是奇數(shù)位卒密,所以我們?nèi)〕銎鏀?shù)位,由于棠赛,1只在奇數(shù)位哮奇,所以取出奇數(shù)位后,應(yīng)該還和原來的數(shù)相等
取奇數(shù)位的方法在反轉(zhuǎn)bit那題中已經(jīng)講過睛约,就是x & 0x55555555

public class Solution {
    public boolean isPowerOfFour(int num) {
        return (num > 0) && ((num & (num - 1)) == 0) && ((num & 0x55555555) == num);
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末鼎俘,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子辩涝,更是在濱河造成了極大的恐慌贸伐,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,331評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件怔揩,死亡現(xiàn)場離奇詭異捉邢,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)商膊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,372評論 3 398
  • 文/潘曉璐 我一進(jìn)店門伏伐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人晕拆,你說我怎么就攤上這事藐翎。” “怎么了实幕?”我有些...
    開封第一講書人閱讀 167,755評論 0 360
  • 文/不壞的土叔 我叫張陵吝镣,是天一觀的道長。 經(jīng)常有香客問我昆庇,道長末贾,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,528評論 1 296
  • 正文 為了忘掉前任凰锡,我火速辦了婚禮未舟,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘掂为。我一直安慰自己裕膀,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,526評論 6 397
  • 文/花漫 我一把揭開白布勇哗。 她就那樣靜靜地躺著昼扛,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上抄谐,一...
    開封第一講書人閱讀 52,166評論 1 308
  • 那天渺鹦,我揣著相機(jī)與錄音,去河邊找鬼蛹含。 笑死毅厚,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的浦箱。 我是一名探鬼主播吸耿,決...
    沈念sama閱讀 40,768評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼酷窥!你這毒婦竟也來了咽安?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,664評論 0 276
  • 序言:老撾萬榮一對情侶失蹤蓬推,失蹤者是張志新(化名)和其女友劉穎妆棒,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體沸伏,經(jīng)...
    沈念sama閱讀 46,205評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡糕珊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,290評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了馋评。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片放接。...
    茶點(diǎn)故事閱讀 40,435評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖留特,靈堂內(nèi)的尸體忽然破棺而出纠脾,到底是詐尸還是另有隱情,我是刑警寧澤蜕青,帶...
    沈念sama閱讀 36,126評論 5 349
  • 正文 年R本政府宣布苟蹈,位于F島的核電站,受9級特大地震影響右核,放射性物質(zhì)發(fā)生泄漏慧脱。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,804評論 3 333
  • 文/蒙蒙 一贺喝、第九天 我趴在偏房一處隱蔽的房頂上張望菱鸥。 院中可真熱鬧,春花似錦躏鱼、人聲如沸氮采。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,276評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鹊漠。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間躯概,已是汗流浹背登钥。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留娶靡,地道東北人牧牢。 一個月前我還...
    沈念sama閱讀 48,818評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像姿锭,于是被迫代替她去往敵國和親结执。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,442評論 2 359

推薦閱讀更多精彩內(nèi)容

  • 背景 一年多以前我在知乎上答了有關(guān)LeetCode的問題, 分享了一些自己做題目的經(jīng)驗(yàn)艾凯。 張土汪:刷leetcod...
    土汪閱讀 12,747評論 0 33
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法懂傀,內(nèi)部類的語法趾诗,繼承相關(guān)的語法,異常的語法蹬蚁,線程的語...
    子非魚_t_閱讀 31,660評論 18 399
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理恃泪,服務(wù)發(fā)現(xiàn),斷路器犀斋,智...
    卡卡羅2017閱讀 134,693評論 18 139
  • 夜叽粹,終于籠罩了這片晦暗小丑摘下了面具览效,不再遮掩街角盡頭,誰伸出一雙染血的手那邪魅的一笑虫几,就藏在夜里 枯黃的紫羅蘭锤灿,...
    暮未茫閱讀 172評論 0 5
  • 暑假,我有幸參加了骨干教師高級研修班的培訓(xùn)辆脸,我很珍惜這次給我提供學(xué)習(xí)但校、提升自我的機(jī)會。懷著激動的心情啡氢,我來到...
    匆匆十年閱讀 587評論 0 1