題目描述
輸入一個整數,輸出該數二進制表示中1的個數。其中負數用補碼錶示。
思路
- 遇到的問題就是我再一次想把這個數字轉換爲二進制碼,但是其實計算機已經幫我們做了這個過程,轉換爲二進制數其實大多應用於高精度中
- 鑑於這個情況,我們可以用位運算,從而比較出該數字的每一位1,但是需要注意陷入死循環的問題,只要非空非0,循環就可以一直繼續
- 至於代碼中設置退出循環的條件就是flag超出unsigned int所能表示的數據範圍,就會發生截斷,然後只保留32位,也就是unsigned int佔4個字節,變成0然後循環退出。
AC代碼
#include <iostream>
#include <math.h>
using namespace std;
class Solution
{
public:
int NumberOf1(int n)
{
int count = 0;
unsigned int flag = 1;
int times = 0;
while (flag)
{
if (flag & n)
count++;
flag = flag << 1;
cout << flag << endl;
times++;
}
// cout << "次數爲" << times <<endl;
return count;
}
};
int main()
{
Solution so;
cout <<so.NumberOf1(13)<<endl;
}
我寫不出來的算法
規律:一個數減去1然後與原來的數進行與運算,會將這個數最右邊的1變成0;(雖然寫不出,但還是學學嘛=-=)這種算法就是一個數裏面有多少個1就循環多少次,
int NumberOf1_2(int n)
{
int count = 0;
while (n)
{
count++;
n = (n-1) & n;
}
return count;
}
遇到的問題&總結
- unsigned int與int做運算時,Int會強制轉換爲無符號整數
unsigned int a = 1,int b = -2;// a b 都是無符號整數 這樣編譯不了,可能是有新版本吧,
unsigned int a = 1;
int b = -2;
int c = -2;
cout << b << endl; //-2
if (a + c > 0) //因此b,c在計算機中是以補碼的形式存放,0xfffffff(1110) ==>無符號表示的就是2^32-2
cout << a + b << endl; //4294967295 ==>>2^32-1
- 注意一個變量的類型,無符號整數和有符號整數此外,這個16進制數表示的負數的補碼,正數就無所謂=-=
int res = 0xffffffff;
unsigned int rea = 0xffffffff;
cout << 0xffffffff <<endl;
cout << res <<endl;
cout << rea <<endl;
/*
4294967295
-1
4294967295
*/
- 遇到判斷二進制數,不用在自己轉爲二進制數了,計算機底層會幫我們處理完成的,只有在高精度時才需要進行這樣的處理
- 條件判斷只要是不爲0或者不爲空就可以運行
- 最後一個問題就是左移32或者以上時,編譯器如何處理這個越界情況,上代碼=-=
unsigned int test1 = 2147483648;
test1 = test1 << 1;
cout << "test1: " <<test1 <<endl;
unsigned int test = 1;
test = (test << 32);
unsigned int i = 1;
cout << "test2 :" <<test << endl;
cout <<"test3:" << (i<<32) <<endl;
/*
test1: 0
test2 :1
test3:1
*/
對上述代碼的總結:
- 首先這個基於g++編譯器
- 其次,如果對於左移1位的數,越界溢出按照截斷處理(就是隻是保留低位的二進制數)
- 但是如果左移32或者以上g++編譯器就會默認處理爲:左移位數與該數據類型位數做取模運算,例如無符號整數1 << 32,那麼32 % 32(無符號整數4個字節) = 0,也就是不移動,結果等於1