复盘二进制的习题(1)
本文是對近期二進制專題的leetcde習題的復盤。文中的解決思路來源于leetcode的討論,以及一些網(wǎng)頁。
342 判斷一個整數(shù)(32bits)是否是4的次冪。
寫出4i,i=0,1,2,3,4...的二進制表示,查找規(guī)律。會發(fā)現(xiàn)這些數(shù)的特征是 a 都>0;b 只有一位是1,代碼:n&(n-1)==0;c 1都在奇數(shù)位置,如果從1開始數(shù),代碼:n&(0x55555555)!=0。
191 數(shù)數(shù)一個無符號整數(shù)n的二進制表示中有幾個1。
方法一:每次判斷最末位置是否為1:n&1==1=>最末位是1;接著n=n>>1,繼續(xù)判斷。
方法二:每次判斷n的某一個位置,從最末位開始。n&1!=0=>該位是1;接著計算(n&(1<<1)),再繼續(xù)n&(1<<2),如此下午,判斷32個位置。方法一和二思路是相同的,都是通過位移來判斷不同的位置,都需要32次循環(huán),只是一個移動數(shù)字,一個移動掩碼mask。
方法三:如果數(shù)字n的二進制位只有1位是1,循環(huán)32次太浪費了。n&(n-1) 實際上是把一個數(shù)的最低位的有效1,給去掉了;而且一次還只能去掉一個位置上的1。這樣只要n=(n&(n-1)),n不等于0,就知道1的位數(shù)是加1的。
思考:如果是有符號的呢?
136 Single Number。給定的數(shù)組中,每個數(shù)都出現(xiàn)了兩次,只有一個數(shù)出現(xiàn)了一次。找到只出現(xiàn)了一次的數(shù)。
方法:兩個相同的數(shù)異或之后會是0。所有數(shù)字異或之后加和,留下的數(shù)就是要找的數(shù)。
461 Hamming Distance。海明距離是計算兩個int,都多少個位是不同的。
方法:任意兩個數(shù)異或之后不同的位會變?yōu)?。步驟是:n=(i^j);數(shù)n有幾個1,等同于191。
169 Majority Element. 主元素是指在數(shù)組中出現(xiàn)次數(shù)超過n/2的元素。前提假設:數(shù)組不為空;主元素總數(shù)存在。(這題做過,怎么一點印象都沒有)
方法1:循環(huán)計算nums[i]出現(xiàn)次數(shù)。時間復雜度O(n2)。
方法2:用hashmap,保存每個數(shù)字出現(xiàn)次數(shù)。時間復雜度O(n),空間復雜度O(n)。
方法3:先排序,再找到最長的連續(xù)串。時間復雜度O(nlogn)。
方法4:分治法,數(shù)組一分為2,查找第一部分的主元素A,第二部分的主元素B。如果A的次數(shù)=B的次數(shù),A和B都是候選主元素。如果不同,則選出主元素。時間復雜度O(nlogn)。
方法5:隨機選元素(不甚理解)。平均時間復雜度O(n),最壞是無窮。隨機啊。。。。
方法6:Moore Voting algorithm。定義候選元素element和次數(shù)count。不斷遍歷nums,如果count=0,element=當前元素,count=1;如果count>0,當前元素=element則count++;否則count–。留下的element一定是主元素。時間復雜度O(n)。這個想法太奇妙了。有點像雙方交戰(zhàn),主元素是一方,其他元素是一方。不斷增加或者減少count。
方法7:位運算。直接上代碼吧。有點不會描述了。一個int,32位。哪個位置上1的個數(shù)>n/2,那這一位一定是主元素貢獻的。所以只要找到1出現(xiàn)次數(shù)超過n/2的位,其他位置為0,就可以找到主元素。
405 將一個整數(shù)用十六進制表示
方法:做十進制與十六進制基礎元素的映射。做映射有兩種方式,一種是map,一種是數(shù)組。當key是數(shù)字的時候用數(shù)組還是比較方便的。nums[]={0,1,2,….a,b,…f}。數(shù)組的下標正好是十六進制對應的十進制。
接著十六進制可以用4位二進制表示。每次將num與0x0f做與操作,這樣就能只留下最后四位了。
190 給定一個無符號的整數(shù)num,輸出一個整數(shù)out,這個整數(shù)是輸入數(shù)字的二進制的逆轉(zhuǎn)。如果方法要多次調(diào)用,可以怎么優(yōu)化。
方法一:變量r為最后結(jié)果,從num低位開始,每次處理1位,r<<1+最低位處理的值。循環(huán)32次。
多次調(diào)用優(yōu)化的方法應該是存儲字節(jié)與結(jié)果的映射關系。
方法二:可以先看代碼。來自網(wǎng)頁。每4位當做一個整體處理,int32位分為8個部分:abcdefgh。處理順序是:abcdefgh -> efghabcd -> ghefcdab -> hgfedcba。代碼最后兩行是處理:4位內(nèi)部的倒序。
這思路看到后真是震驚。原來分治法還能這么玩。膜拜啊。
476 Number Complement。一個int的補是指二進制取反。但是高位的0不變。例如5的補是2。因為 5=101 ,取反,010=2。但是一個int有32位,對于5,從第4位開始的0都不算。所以需要知道最高位的1,在哪個位置即可。
下面是兩種解法。
401 Binary Watch。二進制手表。好酷的手表。這是一個窮舉搜索的問題。
時:8 4 2 1 。每一個選與不選分別用1和0 表示。這樣就形成了一個一個的二進制數(shù)。如果說時鐘只有一個燈亮,那么選擇可能有:
時:8 4 2 1
f1: 0 0 0 1
f2: 0 0 1 0
f3: 0 1 0 0
f4: 1 0 0 0
231 判斷一個數(shù)是否是2的平方。2的平方的特征是:a 大于0;2 只有一個1。
public boolean isPowerOfTwo(int n) {return n>0 && (n&(n-1))==0;}389 Find the Difference。輸入兩個字符串s、t。t是s中所有字母隨機排列后組成的字符串,但是t中有一個字符在s中沒有出現(xiàn)。找出在t中沒有出現(xiàn)的那個字符。
思路一:用map。遍歷s中每個字符的出現(xiàn)次數(shù),保存在map中。接著遍歷t中的字符串,將map[key]value值減1。如果在map的key值不存在或者說map[key]的value <=0 ,那這個字符一定不在s中出現(xiàn)。
思路2:位操作。用異或可以將相同的字符抵消。s和t兩個字符串做異或,留下的就是沒在s中出現(xiàn)的字符。
268 Missing Number。給一個包含n個不同數(shù)值的數(shù)組nums,數(shù)組本應該是0,1,2,…n這樣的數(shù)字,但是丟了一個數(shù)字。返回丟失的數(shù)字。例如輸入 nums = [0, 1, 3] 返回2。
思路:這個題目與上一提很相似。389是查找多出的字符,268是查找丟失的數(shù)字。都是從兩個可比較的對象中,查找出多的或者少的部分。
371 Sum of Two Integers。不用+ - 操作求兩個數(shù)的和。這個解法就是比較神奇了。處理兩個數(shù)相同的部分;處理兩個數(shù)相異的部分。兩個數(shù)相同的部分加和的時候還要向前進一,和我們手動計算和相似。
public int getSum(int a, int b) {return b == 0 ? a : getSum(a ^ b, (a & b) << 1); }參考資料
1 bit-manipulation
2 網(wǎng)址
3 網(wǎng)址
可能會有落下的網(wǎng)址,未列出。謝謝作者們。
總結(jié)
以上是生活随笔為你收集整理的复盘二进制的习题(1)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android通用流行框架大全
- 下一篇: MOSSE跟踪算法源码解析