挑战面试编程:计算整数二进制位中1的个数
来源:互联网 发布:中科院对学生调查数据 编辑:程序博客网 时间:2024/05/16 19:21
挑战面试编程:计算整数二进制位中1的个数
题目:
在计算机中,整数是以2的补码的形式给出的。 给出整数A和B,假设计算机是32位机,求从A到B之间的所有二进制数中,一共用了多少个1。 输入格式: 多组数据,每组数据一行,由两个整数A,B, -2147483648<=A<=B<=2147483647 输出格式: 每组输出一行,从A到B使用的1的个数。(本题取自csdn高校俱乐部线上编程挑战赛)
分析:
我们知道任何数据在计算机中都是用二进制表示的,即用一堆0或1表示各种类型的数据。当然还要考虑它的字节数,例如在32位机中。sizeof(int)=4,sizeof(float)=4,sizeof(double)=8,sizeof(long long)=8。当然一种数据类型配了多少字节来存储,这不仅与cpu的字长、系统有关,还与编译器有关。上面的数据是我的机器上测试值。既然要统计二进位中1的个数,当然优先考虑位运算。
下面介绍几种位运算(位运算即按位运算):
位与 &
运算规则:0&0=0;
位或 |
运算规则:0|0=0;
位异或 ^
运算规则:0^0=0;
思路:
用该整数与1做32次位与运算,即可统计1的个数。因为一个四个字节的整数1,它的高位有31个0,只有最后一位是1,即00000000 00000000 00000000 00000001。这样就可以判断概数的二进制最低位是1还是0。位于结果若是1,则表明最后一位1,若是0,则表明最后一位是0(对照运算规则,可很容易看出)。每一次判断后,都得对该整数右移一位,以判断次最低位。
代码
<span style="font-family:Courier New;font-size:14px;">#include<iostream>using namespace std;long long count_one(int n){long long count=0; //考虑到数字可能很大,就用使用long long类型for(int i=0; i<32; i++){ if(n&1) //位与运算count++;n>>=1; //向右移动一位}return count;}int main(){int i,j;int a,b;long long sum=0;while(cin>>a>>b && a) //输入0 0结束程序{for(int j=a; j<=b; j++)sum+=count_one(j);cout<<sum<<endl;sum=0; //重置}cin.get();return 0;}</span>
运行实例:
update:
感谢一楼的提示,有了以下的新思路:
思路:如果当前数的最小二进位是0,则下一个数不用统计,便可知它的二进制位1的个数比当前数多一个。于是,我们可以两个两个的计算,大概只需遍历 n/2 次,这样是不是快很多。
<span style="font-family:Courier New;font-size:18px;">int count_one(int a, bool &flag){int temp = a;int count = 0;if (temp & 1)flag = false;while (temp){count++;temp = temp&(temp-1);}return count;}int main(){int a, b;bool flag = true;int count = 0;double sum = 0;while (scanf_s("%d %d", &a, &b) != EOF){for (int i = a; i <= b; i++){count = count_one(i, flag);if (flag){if (i < b) //若还有下一个数{sum += 2 * count + 1;i++;}if (i == b) //无下一个数sum += count;}else{sum += count;}flag = true;/* //这个是以上流程的优化写法if (flag && i < b){sum += 2 * count + 1;i++;}elsesum += count;flag = true;*/}printf("%.0lf\n", sum);sum = 0;}system("pause");return 0;}</span>
几点说明:
- 右移运算的左边二进位如何填充。这个c语言规范中没有明确规定,那就是说具体实现得看编译器如何处理。还好大多数编译器是这样处理的:对于无符号数或正数,用0填充;对于负数用1填充。大家可以在自己的机器上试试。
- 右移运算a>>1,是不会改变a自身的值的,要想改变a自身的值,得使用a>>=1。
- 为了终止程序,我个人加了对a值非0的判断,即此程序不可原封不动作为挑战赛的答案,得进行必要修改。
- 关于位运算的奇妙用处还有很多,希望各位同学多提想法,欢迎不吝赐教。先谢了!
补充:
异或运算^ 可用来交换数据(注意:这里的a,b不能指向同一个元素,否则最后都是0,所加一个是否相等的判断)
void swap(int &a, int &b){if(a!=b){a^=b;b^=a; a^=b;}}
关于交换数据的其它方法:
最常见的是增加一个变量 temp,方法如下:
方法一:
void swap(int &a, int &b){if(a!=b){int temp=a;a=b;b=temp;}}
方法二:
void swap(int &a, int &b){if(a!=b){a=a+b;b=a-b;a=a-b;}}
update 2015年10月9日
最快的算法或许是这样:
对于一个整型的数a,做运算a = a & (a - 1);后a二进位为1且位于最右边的那一个二进制位会消失。
如a=3;做运算a&(a-1)
0000 0011
& 0000 0010
0000 0010
由于这种现象的存在,只需记录a为0前,运算a&(a-1)可以进行的次数,即可得知a的二进制位上1的个数。
所有内容的目录
- CCPP Blog 目录
- 挑战面试编程:计算整数二进制位中1的个数
- 17_7_20:计算一个整数二进制位中1的个数。
- 计算一个整数二进制位中1的个数
- 计算一个整数二进制位中1的个数
- C/计算一个整数二进制位中1的个数
- 计算一个整数二进制位中1的个数
- 计算一个整数二进制位中1的个数
- 计算一个整数二进制位中1的个数
- 一个整数二进制位中1的个数
- 计算二进制位中1的个数
- 元素出栈、入栈顺序的合法性/计算一个整数二进制位中1的个数。
- 剑指offer 10----计算一个整数二进制位中1的个数
- 计算二进制位"1"的个数
- 计算二进制位'1'的个数
- 计算二进制位'1'的个数
- 整数二进制位中1的个数【每日一题】
- day08之元素出栈、入栈顺序的合法性+计算一个整数二进制位中1的个数
- n&(n-1) 计算二进制位中1的个数
- unity3d 学习笔记(二)
- 单身女青年的购房之路
- Uva 1121Subsequence
- uva 146 ID Codes (下一个排列)
- OCP 1Z0 051 3
- 挑战面试编程:计算整数二进制位中1的个数
- 第十一周项目三点类派生直线类(有疑问)
- OpenGL ES From the Ground Up, Part 1 Addendum: Alphabet Soup
- JavaScript中this关键字使用方法详解
- XML 简介 (from W3C School)
- OpenGL ES From the Ground Up, Part 1: Basic Concepts
- mysql “group by ”与"order by"的研究--分类中最新的内容
- struts2的工作原理
- SIFT算法学习