幸运数-京东2017在线笔试编程题

题目描述:
小明同学学习了不同的进制之后,拿起了一些数字做起了游戏。小明同学知道,在日常生活中我们最常用的是十进制数,而在计算机中,二进制数也很常用。现在对于一个数字x,小明同学定义出了两个函数f(x)和g(x)。
f(x)表示把x这个数用十进制写出后各个数位上的数字之和。如f(123)=1+2+3=6。
g(x)表示把x这个数用二进制写出后各个数位上的数字之和。如123的二进制表示为1111011,那么g(123)=1+1+1+1+0+1+1=6。
小明同学发现对于一些正整数x满足f(x)=g(x),他把这种数字称为幸运数,现在他想知道,小于等于n的幸运数有多少个。
输入
第一行一个整数T(T<=10000)表示数据组数,每组数据输入一个数n(n<=100000)。
输出
每组数据输出一行,小于等于n的幸运数个数。


样例输入
3
1
5
21
样例输出
1
1
3


代码如下:

#include<iostream>
using namespace std;

void main()
{
	int T;//数组的组数
	cin>>T;
	int *count=new int[T];
	int n;
	int k=0;//计数
	while(k<T)
	{
		cin>>n;
		count[k]=0;
		for(int x=1;x<=n;x++)
		{
			int fx=0;//十进制各个数位上的数字之和
			int gx=0;//二进制各个数位上的数字之和
			int tmp=x;
			while(tmp)
			{
				fx+=tmp%10;
				tmp=tmp/10;
			}
			tmp=x;
			while(tmp)
			{
				gx++;
				tmp=tmp&(tmp-1);
			}
			if(fx==gx)
				count[k]++;
		}

		k++;
	}
	for(int i=0;i<T;i++)
		cout<<count[i]<<endl;
}

补充:关于求二进制中1的个数。

可能会想到的解法是:先判断整数二进制表示中最右边一位是不是1,接着把输入的整数右移一位,此处原来处于从右边数起的第二位被移到最右边了,再判断是不是1.这样每次移动一位,直到整个整数变为0为止。这样的解法会出现的问题是,如果输入的一个数是负数,右移时高位补1,最终这个数字会变为所有位上均为1而陷入死循环。当然,我们这里上边的关于“幸运数”的题应该不存在这个问题,输入的整数不为负数。

所以,以上解法对于负数不可行。为了避免死循环,想到我们可以不右移输入的数字。首先把输入的数字与1做与运算,判断最低位是不是1,接着把1左移一位,判断输入整数的次低位是不是1……这样反复左移,就能统计出输入整数的所有位上1的个数。代码如下:

class Solution {
public:
     int  NumberOf1(int n) {
         int count=0;
         unsigned int flag=1;
         while(flag) {
             if(n&flag)
                 count++;
             flag=flag<<1;
         }
         return count;
     }
};
另一种解法:我们还可以发现,对于一个整数减去1,都是把最右边的1变为0,如果它的右边还有0的话,所有0都变为1,而它的左边位保持不变。举一个栗子,以1100为例,减一后变为1011,将原来的数与减一后的数做与运算,得到1000,可以看出最右边1变为了0,它的左边仍保持不变,可以通过统计这样的与运算次数,来统计各个位上1的个数。利用此方法的代码如下:

class Solution {
public:
     int  NumberOf1(int n) {
         int count=0;
         while(n) {
             count++;
             n=n&(n-1);
         }
         return count;
     }
};




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值