剑指offer|剑指offer - 二进制中1的个数
题目
请实现一个函数,输入一个整数,输出该二进制表示中1的个数。例如:把9表示成二进制是1001,有2位1。因此,如果输入9,则该函数输出2
思路1
要判断二进制中1的个数,那么就需要一位一位的判断是否是1。
最直观的想法就是判断整数二进制表示中的最右边是不是1,接着把输入的整数右移一位,此时原来处于从右边数起的第二位被移动最右边了,再判断是不是1,这样每次移动一位,直到整数变成0为止算法实现
int NumberOf1_Solution1(int n)
{
int count = 0;
while (n) {
if (n & 1)
count++;
n = n >> 1;
// 右移一位
}
return count;
}
上面代码看似正确,对于正整数,0都OK,但是如果我们输入负整数的话,那么程序就会陷入死循环。因为负数的最高位是1,移位之后仍然要保证是负数,最后会变成0xFFFFFFFF,二进制为1111 1111 1111 1111 1111 1111 1111 1111从而变成死循环
注意:虽然右移位和除2是等价的,但是执行的效率不一样,位移操作比除法效率高
为了避免上述问题,我们可以设定一个标志位算法实现flag
,让标志位flag
与整数n
进行与运算并移动
int NumberOf1_Solution1(int n)
{
int count = 0;
unsigned int flag = 1;
// 标志位
while (flag)
{
if (n & flag) // 当前位置是否是1
count++;
// 个数加1flag = flag << 1;
// 移动标志位
}return count;
}
上面代码简单来说就是把
n和1
做与运算,判断n
的最低位是不是1。接着把1左移一位得到2,再和n做与运算,就能判断n的次低位是不是1,这样反复左移,每次都能判断n
的其中一位是不是1
。循环的次数等于整数二进制的位数,32位的整数需要循环32次。
思路2 思路1进行优化,整数中有几个1就只需要循环几次
即把一个整数减去1,再和原整数做与运算,会把该整数最右边的1变成0,那么一个整数的二进制表示中有多少个1,就可以进行多少次这样的操作。举个例子
二进制数
1100
,减去1后,第二位变成0,它后面的两位0变成1,而前面的1保持不变,因此得到的结果是1011
,然后与1100
进行与算法,结果为1000
再次循环,将
1000
减去1,那么为0111
,然后与1000
进行与运算,结果为0,退出循环。所以
1100
中二进制1的个数为2算法实现
int NumberOf1_Solution2(int n)
{
int count = 0;
while (n) {
++count;
n = (n - 1) & n;
}
return count;
}
思路3 静态查表法
把
0~255
这256个数的结果全部存储在数组中,n
直接作为下标,countTable[n]
即为结果。典型的用空间换时间。int NumberOf1_Solution3(int val)
{
int countTable[] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3,
2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4,
2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5,
4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4,
3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6,
4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4,
3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5,
4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5,
3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6,
5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8};
return countTable[val];
}
更多有趣的解法可以参考这里
参考 【剑指offer|剑指offer - 二进制中1的个数】《剑指offer》
推荐阅读
- 剑指|剑指 Offer 13. 机器人的运动范围(dfs,bfs)
- 剑指offer60.n个骰子的点数
- 剑指offer——最小的K个数
- 汇编实验(格雷码转二进制(ASCII码)的实现和调试)
- 【数组题】给定一个二进制矩阵|【数组题】给定一个二进制矩阵 A,我们想先水平翻转图像,然后反转图像并返回结果。
- Android|年后备战金三银四(Android面试吃透这一篇就没有拿不到的offer......)
- 剑指黄昏
- 符号化二进制崩溃问题
- 剑指offer15.二进制中1的个数
- (二)|(二) Mach-O 文件结构