題目描述:
輸入一個整數,輸出該數二進制表示中1的個數。其中負數用補碼錶示。
解法1思路解析:
step 1:num的二進制的最右邊位與1相與,如果不爲0,則count加1;
step 2:否則,對1左移一位,繼續與num的二進制的最右邊數的第二位進行相與;
step 3:依次循環,即可完成。
解法1代碼實現:
import java.util.Scanner;
public class Exercise18 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNext()){
int num = sc.nextInt();
int count = NumberOf1(num);
System.out.println(count);
}
}
private static int NumberOf1(int num) {
//判斷num是否爲0
if(num == 0){
return 0;
}
//記錄1的出現次數
int count = 0;
int flag = 1;
//flag一直向左移,當到1000 0000 0000 0000時,如果再左移,就回到了0
while(flag != 0){
//num有可能是負數,當它與flag相與的時候,結果小於0,
//所以只要讓兩者相與的結果不爲0即可
if((num & flag) != 0){
count++;
}
//flag左移一位
flag = flag << 1;
}
return count;
}
}
解法1缺陷解析:
循環次數較多,解法1代碼的循環次數跟數據類型有關,如果是int型(4字節),那麼它在計算機中存儲的bit位爲32位,如果是short型(2字節),那麼它在計算機中存儲的bit位爲16位,如果數據沒有佔滿整個bit位的話,即使得到我們想要的結果,flag還是要進行左移,直到flag爲0,換句話講,int型的數據,不管它是多大,flag都要左移32位,即循環了32次,對於short型數據,flag要左移16位,即循環了16次。
解法2思路解析:
step 1:num的二進制與1相與,如果不爲0,則count加1;
step 2:否則,對num無符號右移一位,繼續與1進行相與;
step 3:依次循環,即可完成。
解法2代碼實現:
import java.util.Scanner;
public class Exercise18 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNext()){
int num = sc.nextInt();
int count = NumberOf2(num);
System.out.println(count);
}
}
private static int NumberOf2(int num) {
//判斷num是否爲0
if(num == 0){
return 0;
}
//記錄1的出現次數
int count = 0;
int flag = 1;
while(num != 0){
//num有可能是負數,當它與flag相與的時候,結果小於0,
//所以只要讓兩者相與的結果不爲0即可
if((num & flag) != 0){
count++;
}
//num無符號右移一位,如果改成有符號右移,正數沒影響,負數會使系統陷入死循環
num = num >>> 1;
}
return count;
}
解法2缺陷解析:
(1)對於解法2,如果不注意將代碼寫成有符號右移,即num = num >> 1,拿到的num又恰好是個負數(負數,在進行右移的時候,最高位會進行補位運算,不管右移多少次,始終都會出現這一個1—符號位的1,這個時候就會造成一個負數得到無數個1),那麼將會使系統陷入死循環。
(2)對原數字進行了更改,不利於後期使用。
解法3思路解析:
step 1:如果一個整數不爲0,那麼這個整數的二進制至少有一位是1;
step 2:如果我們把這個整數減1,那麼原來處在整數最右邊的1就會變爲0,原來在1後面的所有的0都會變成1(如果最右邊的1後面還有0的話),更改後的1(1變爲0)的前面的其餘位數不受影響;
step 3:num 與 num - 1進行相與,消除該數二進制位最右邊的1;
step 4:依次循環,即可完成。
解法3代碼實現:
import java.util.Scanner;
public class Exercise18 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNext()){
int num = sc.nextInt();
int count = NumberOf3(num);
System.out.println(count);
}
}
private static int NumberOf3(int num) {
//判斷num是否爲0
if(num == 0){
return 0;
}
//記錄1的出現次數
int count = 0;
//當num不爲0時,其它任意整數的二進制至少有一個1,進入循環後,count先加1
while(num != 0){
count++;
/**
* num-1,如果n的二進制右邊數第一位是1,則變爲0,如果到某幾位才爲1時,
* 如:0110 0100,則最右邊的1變爲0,
* 原先1的右邊的00都變爲11 即0110 0011,然後與num相與;
* 得到的值正好是:0110 0000,(剛好消除了最右邊的那一個1)
* 最終結論,num & (num - 1)只會將最右邊的1變爲0
*/
num = num & (num - 1);
}
return count;
}
解法3缺陷解析:
對原數字進行了更改,不利於後期使用。
題目總結:
(1)解法1的循環次數較多,但沒有更改原數據;
(2)解法2更改了原數據,如果代碼寫成有符號右移,對於負數,會造成系統的死循環;
(3)解法3更改了原數據。
計算機中數的存儲形式:
https://blog.csdn.net/weixin_43761659/article/details/98472451
Java移位運算符:
https://blog.csdn.net/weixin_43761659/article/details/98472473
心靈雞湯:考慮一千次,不如去做一次;猶豫一萬次,不如實踐一次;華麗的跌倒,勝過無謂的彷徨,將來的你,一定會感謝現在奮鬥的自己。