Part1. 我的思路和代码
依次判断每一位是否是1
。将二进制表示与0x1进行与运算,结果为1、0分别说明最低位为1、0,然后将二进制右移1位,重复同样的过程,一共循环32次。
int NumberOf1(int n) {
int ans = 0;
for(int i=0; i<32; i++){
if(n&1){
++ans;
}
n = n >> 1;
}
return ans;
}
特别记录:如果不进行32次循环,而是通过判断n是否为0的方式控制循环结束,需要注意如果n原本是负数,那么进行右移操作后,最高位会用1补充,会造成死循环。
Part2. 其他做法
1. 不同的循环方式
不改变原整数的二进制值,而是从低位到高位依次,通过将0x1左移的方式提取每一位的值。
int NumberOf1(int n) {
int ans = 0;
int temp = 1;
while(temp){
if(n&temp){
++ans;
}
temp = temp << 1;
}
return ans;
}
2. 有几个1就循环几次的做法
该做法的根据是
:将一个数减去1,将结果和原整数进行与运算,会把二进制表示中最右边的1变为0。于是二进制中有几个1,就可以进行几次这样的操作。
int NumberOf1(int n) {
int ans = 0;
while(n){
n = n & (n-1);
++ans;
}
return ans;
}
Part3. 相关题目
题目1
判断一个整数是不是2的整数次方。
如果是2的整数次方,那么二进制中1的个数为1
。可以用循环来计算1的个数,而使用“有几个1就循环几次的做法”是效率更高的选择。
题目2
两个整数m、n,求m中需要改变多少个二进制位才能将m变为n。
直接对比m、n的二进制中1的个数的差值是不可行的
,因为1的个数相同时,二进制也可以不同,如1100和0011,所以需要先得到m和n哪些位是不一样的。根据异或运算的规律,如果对应的位相同,运算后结果为0,如果对应的位不同,结果为1,于是先将m和n进行异或运算得到r,判断r中1的个数即为所求。
Part4. 心得体会
- 我自己是想不到“有几个1就循环几次”的做法的,做此题目也是属于一种知识的积累。
原本打算不记录这道题的
,但从这道题新学到了一些内容,于是也记录了。