题目描述
输入一个整数,输出该数二进制表示中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