位運算總結(刷題)

2021-10-07 05:48:35 字數 4013 閱讀 8467

4.繼續刷題:不用額外的變數交換兩個整數的值(異或應用)

5. 不用任何比較判斷找出兩個數中較大的數

6. 只用位運算不用算術運算實現整數的加減乘除運算

請實現乙個函式,輸入乙個整數,輸出該數二進位制表示中 1 的個數。例如,把 9 表示成二進位制是 1001,有 2 位是 1。因此,如果輸入 9,則該函式輸出 2。

輸入:00000000000000000000000000001011

輸出:3

解釋:輸入的二進位制串 00000000000000000000000000001011 中,共有三位為 『1』。

演算法:在分析這種演算法之前,我們先來分析把-乙個數減去1的情況。如果乙個整數不等於0,那麼該整數的二進位制表示中至少有一位是1。先假設這個數的最右邊一位是1,那麼減去1時,最後一位變成0而其他所有位都保持不變。也就是最後一位相當於做了取反操作,由1變成了0。

接下來假設最後一位不是1而是0的情況。如果該整數的二進位制表示中最右邊的1位於第m位,那麼減去1時,第m位由1變成0,而第m位之後的所有0都變成1,整數中第m位之前的所有位都保持不變。舉個例子:乙個二進位制數1100, 它的第二位是從最右邊數起的-乙個1。減去1後,第二位變成0,它後面的兩位0變成1,而前面的1保持不變,因此得到的結果是1011。

在前面兩種情況中,我們發現把乙個整數減去1,都是把最右邊的1變成0。如果它的右邊還有0,則所有的0都變成1,而它左邊的所有位都保持不變。接下來我們把-乙個整數和它減去1的結果做位與運算,相當於把它最右邊的1變成0。還是以前面的1100為例,它減去1的結果是1011。我們再把1100和1011做位與運算,得到的結果是1000。 我們把1100最右邊的1變成了0,結果剛好就是1000。

我們把上面的分析總結起來就是:把乙個整數減去1,再和原整數做與運算,會把該整數最右邊的1變成0。那麼乙個整數的二二進位制表示中有多少個1,就可以進行多少次這樣的操作。基於這種思路,我們可以寫出新的**:(參考劍指offer)

/**

* 方法2:由於n和n-1作與&比較的時候,最右邊的第乙個1會變成0,而這個1後邊的0會變成1,1會變成0

* 把乙個整數減去1,再和原整數做與運算,會把該整數最右邊的1變成0。那麼乙個整數的二二進位制表示中有多少個1,

* 就可以進行多少次這樣的操作。基於這種思路,我們可以寫出新的**:

*/public

inthammingweight2

(int n)

return count;

}

int count =0;

while

(n !=0)

n = n >>1;

}return count;

/**

* 給定乙個整數,編寫乙個函式來判斷它是否是 2 的冪次方。

* 輸入: 16

* 輸出: true

* 解釋: 2^4 = 16

* 演算法:乙個整數只要是2的冪次方,那麼他的二進位制表示中肯定就只有1個1,

* 因此,對這個數的二進位制表示減1的時候,原來1的位置會變成0,原來是0的地方會變成1

* 將減1的數字與源數字進行與運算,如果源數字只有1個1的時候,那麼與運算後,整個數會變成0

*/public

boolean

ispoweroftwo

(int n)

long x =

(long

)n;if

((x &

(x -1)

)==0)

return

false

;}

把乙個整數減去1之後再和原來的整數做位與運算,得到的結果相當於把整數的二進位制表示中最右邊的1變成0。很多二進位制的問題都可以用這種思路解決。

按位取反:~ :二進位制位中的0變1,1變0

左移運算子m<00001010<< 2 = 00101000

10001010<< 3 = 01010000

右移運算子m>>n表示把m右移n位。在右移n位的時候,最右邊的n位將被丟棄。但右移時處理最左邊位的情形要稍微複雜-一點。如果數字是乙個無符號數值, 則用0填補最左邊的n位:如果數字是乙個有符號數值,則用數字的符號位填補最左邊的n位。也就是說,如果數字原先是乙個正數,則右移之後在最左邊補n個0;如果數字原先是負數,則右移之後在最左邊補n個1。下面是對兩個8位有符號數進行右移的例子:

00001010>> 2 = 00000010

10001010>> 3 = 11110001

如何不用任何額外變數交換兩個整數的值?

說明:異或^,其實表示的是儲存兩個元素的不同屬性,0 ^ 0 = 0;1 ^ 0 = 1; 0 ^ 1 = 1;1 ^ 1 = 0

明顯地,可以看出,0表示的是相同的屬性,1表示的是不同的屬性

使用異或運算交換兩個數字,第一次使用a記錄兩者的不同資訊,第二次使用b記錄與b相反的資訊,第三次使用a記錄與新b相反的資訊,**:

/**

* 編寫乙個函式,不用臨時變數,直接交換numbers = [a, b]中a與b的值。

* 演算法:

* 如果給定整數a和b,用以下三行**即可交換a和b的值。

* a=a^b;

* b=a^ b;

* a=a^ b;

* 如何理解這三行**的具體功能呢?首先要理解關於異或運算的特點:

* 假設a異或 b的結果記為c,c就是a整數字資訊和b整數字資訊的所有不同資訊。

* 比如,a=4=100, b=3=011,a^b=c=111。

* a異或c的結果就是b。比如a=4=100, c= =111, a^c=011=3=b。

* b異或c的結果就是a。比如b=3=011, c= =111, b^c=100=4=a。

*/public

int[

]swapnumbers

(int

numbers)

public

intflip

(int n)

public

intsign

(int n)

public

intgetmax1

(int a,

int b)

sign函式的功能是返回整數n的符號,正數和0返回1,負數則返回0。flip 函式的功能是如果n為1,返回0,如果n為0,返回1。所以,如果a-b的結果為0或正數,那麼sca為1,scb為0;如果a-b的值為負數,那麼sca為0,scb為1。sca和scb必有乙個

為1,另乙個必為0。所以returna* sca+b* scb;,就是根據a-b的值的狀況,選擇要麼返回a,,要麼返回b。

但方法一是有侷限性的,那就是如果a-b的值出現溢位,返回結果就不正確。

第二種方法可以徹底解決溢位的問題,也就是如下**中的getmax2方法。

public

intflip

(int n)

public

intsign

(int n)

public

intgetmax2

(int a,

int b)

借鑑左神的程式設計師面試指南:

}解釋(劍指offer):

位運算 刷題總結

位運算 從現代計算機中所有的資料二進位制的形式儲存在裝置中。即 0 1 兩種狀態,計算機對二進位制資料進行的運算 都是叫位運算。判斷兩個數是否異號 int x 1 y 2 bool f x y 0 true int x 3,y 2 bool f x y 0 false 這個技巧還是很實用的,利用的是...

位運算題 刷題總結

給定乙個整數陣列 nums,其中恰好有兩個元素只出現一次,其餘所有元素均出現兩次。找出只出現一次的那兩個元素。示例 輸入 1,2,1,3,2,5 輸出 3,5 方法 異或 我知道異或可以使所有一對一對的值都消失,得到只出現過一次的數的異或值,但是這題的重點是,你得到兩個只出現一次的數之後,如何區分?...

刷題 位運算

includeusing namespace std 不使用中間變數交換兩個整數的值 void swap int a,int b 整數的二進位制表達中有多少個1 int number of one int n return result 在乙個整數陣列中,只有1個數出現了奇數次,其餘數都出現了偶數次...