標籤:負數 需要 64位 code 填充 數值 移位元運算符 val not
Given a positive integer, output its complement number. The complement strategy is to flip the bits of its binary representation.
Note:
- The given integer is guaranteed to fit within the range of a 32-bit signed integer.
- You could assume no leading zero bit in the integer’s binary representation.
Example 1:
Input: 5Output: 2Explanation: 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: 1Output: 0Explanation: The binary representation of 1 is 1 (no leading zero bits), and its complement is 0. So you need to output 0.
Subscribe to see which companies asked this question
【題目分析】
給定一個正整數,對該數的二進位表示形式,從最高位的1開始向後按位取反。
【思路】
如果我們能知道該數最高位的1所在的位置,就可以構造一個長度和該資料所佔位置一樣長的一個掩碼mask,然後概述和mask進行異或即可。
例如:5的二進位是101,我們的構造的掩碼為mask=111,兩者異或則為010,即是所要的結果。
【java代碼1】
1 public class Solution { 2 public int findComplement(int num) { 3 int mask = 1, temp = num; 4 while(temp > 0) { 5 mask = mask << 1; 6 temp = temp >> 1; 7 } 8 return num^(mask-1); 9 }10 }
【java代碼2】
1 public class Solution {2 public int findComplement(int num) {3 int mask = (Integer.highestOneBit(num) << 1) - 1;4 return num^mask;5 }6 }
Integer.highestOneBit(i)是一個什麼樣的函數呢?
首先來補充一點背景知識。 1、在電腦系統中,數值一律使用補碼來表示和儲存。主要原因是使用補碼可以將符號位和其它位統一處理;同時,減法也可按照加法來處理。另 外, 兩個用補碼錶示的數相加時,如果最高位(符號位)有進位,則進位被捨棄。- 補碼與原碼的轉換過程幾乎相同。 - 數值的補碼錶示(分兩種) - 正數的補碼:與原碼相同 - 負數的補碼:符號位位1,其餘位位該數絕對值的原碼按位取反;然後整個數加1 - 已知一個數的補碼,求原碼的操作分為兩種情況 - 如果補碼的符號位“0”,表示是一個正數,所以補碼就是該數的原碼 - 如果補碼的符號位為“1”,表示是一個負數,求原碼的操作可以是:符號位位1,其餘各位取反,然後整個數加1。2、移位元運算符就是在二進位的基礎上對數字進行平移。Java按照平移的方向和填充數位規則分為三種:<<左移,>>帶符號右移 和>>>無符號右移。3、 在Java的移位元運算中,byte、short和char類型移位後的結果會變成int類型,對於byte、short、char和int進行移位時,對於char、short、char和int進行移位操作時,規定實際移動的次數是移動次數和32的餘數,也就是移位33次和移位1次得到的結果相同。移動long型的數值時,規定實際移動的次數是移動次數和64的餘數,也就是移動65次移位1次得到相同的結果。 (1) << 運算規則:按二進位形式吧所有的數字向左移動對應的位元,高位移出(捨棄),低位的空位補零。 文法格式: 需要移位的數字<<移位的次數 例如:4<<2 ,則是將數字4左移2位 計算過程 4<<2 Java中一個int數佔四個位元組,那麼4的位元字為00000000 00000000 00000000 00000100,然後把該數字左移兩位。其它的數字都朝右平移兩位,最後在低位(右側)的兩個空位補零。則得到的最終結果是00000000 00000000 00000000 00010000,即轉換為十進位數16。 在數字沒有溢出的前提下,對於正數和負數,左移一位都相當於乘以2的1次方,左移n位就相當於乘以2的n次方。 在溢出的前提前,則不符合這個規律。讀者可以嘗試輸出(long)1610612736*4和1610612736<<2這兩個結果進行比對。 (2)>>運算規則:按二進位形式吧所有的數字都向右移動對應的位置,低位移出(捨棄),高位的空位補符號位,即正數補零,負數補1。 文法格式: 需要移位的數字>>移位的次數 例如:-4>>2和4>>2,則是將數字 -4和4右移2位 計算過程 4>>2 Java中一個int數佔四個位元組,同樣4的二進位為00000000 00000000 00000000 00000100,然後把該數字右移兩位。其它的數字都朝左平移兩位,最後在高位補符號位(該數是正數,全補零),得到的結果是00000000 00000000 00000000 00000001,即使十進位的1。數學意義就是右移移位相當於除2,右移n位相當於除以2的n次方。 4>>2 由於負數在電腦中是以補碼的形式儲存的,那麼-4的二進位為11111111 11111111 11111111 11111100,然後把該數字右移兩位,其它數字都朝左平移兩位,最後在高位補符號位(該數是負數,全補一),得到的結果是11111111 11111111 11111111 11111111(補碼格式),即是十進位的-1。 (3)>>>運算規則:按二進位形式吧所有的數字向右移動對應的位元,低位移出(捨棄),高位的空位補零。正數運算結果與帶符號右移相同,對於負數來說則不同。 對於4>>>2和-4>>>2運算,可以通過上述例子進行類推。 瞭解了Java的位元運算之後,來看下 Integer.highestOneBit (i) 這個函數的實現代碼:
1 publicstaticinthighestOneBit(int i) { 2 // HD, Figure 3-1 3 i |= (i >> 1); 4 i |= (i >> 2); 5 i |= (i >> 4); 6 i |= (i >> 8); 7 i |= (i >> 16); 8 return i - (i >>> 1); 9 }
1、第一步的作用是把最高位1右移移位,並與原資料按位取或。那麼這就使得最高位和它的下一位是連續兩個1。2、第二步的作用是把剛剛移位得到連續兩個1繼續右移兩位並與原資料按位取或。那麼這就使得最高兩位和它的下兩個連續位組成四個連續的1。3、 以此類推,最終得到的i是從開始的最高位到結束全是1。並減去i不帶符號的右移一位,即可得到一個int資料的最高位的值。4、上述情況是針對於i不為零和負數的情況,如果i為零,那麼得到的結果始終為零。如果i位負數,那麼得到的結果始終是-2147483648。即等於Integer.MIN_VALUE。(原因在於負數的最高位始終為1,即是負數的符號位) 此函數的最重要理解點在與要始終把握二進位的最高位進行運算處理,那麼對於函數中的右移一位、兩位、四位、八和十六位就好理解了。同理,對於long類型的取最高位元運算應該需要加一條語句 i|=(i>>32); 原因在於long類型在Java中是64位的。
Long類型的hightestOneBit(i)代碼如下:
1 public static long highestOneBit(long i) { 2 // HD, Figure 3-1 3 i |= (i >> 1); 4 i |= (i >> 2); 5 i |= (i >> 4); 6 i |= (i >> 8); 7 i |= (i >> 16); 8 i |= (i >> 32); 9 return i - (i >>> 1); 10 }
LeetCode 476. Number Complement