(本来是列为转载的,但是原文算法那里有不可原谅的错误,愤慨之下,收归己有)
给定一个正整数n,写一个算法计算从1到n之间有多少“至少出现一次7”的数。例如n=20,那么有两个出现7的数:7,17。
算法
去掉个位的数字有N/10个,这也是个位为7的数的个数,包含出现多于一个7的情况,以下类推
再去掉十位的数字有N/100个,乘以9是十位为7的数的个数(个位不能再取7,所以乘9)
再去掉百位的数字有N/1000个,乘以81是百位为7的数的个数(个位或十位都不能再取7,所以乘9的平方)
依次类推。。。对于个位大于等于7的数字,最后的结果还要+1
例如2000内有7的个数=200+20*9+2*81=542, 2000/10 = 200 是个位出现7的数的个数,2000/200×9是十位出现7的情况,2000/1000×9×9是百位出现7的情况,个位小于7,不需要额外加1。
进一步解释:以2000作为例子,考虑个位为7的情况,从07,17,27一直到1997,个位为7的情况出现了200次(0到199); 考虑十位为7的情况,07x,17x,27x一直到197x,其中x代表除了7外的其他数字,所以十位为7的情况为20次(0到19)乘以9(个位的情况), 由于排除了个位是7的情况,所以不会跟第一种情况算重; 考虑百位为7的情况,07xx,17xx,所以百位为7的情况事2乘以9的平方。
为什么个位数大于等于7的话还要额外+1?譬如2018,因为2017事实上没有算入之前的几种情况,只算了(0到200).
这么一分析的话,代码就很简单了:
#include <iostream>
#include <cmath>
using namespace std;
int get7num(int n) {
int p = 0;
int num = 0;
int bonus = (n%10 >= 7);
while(n != 0) {
num += (n/10)*pow(9,p);
p++;
n /= 10;
}
return num + bonus;
}
int main() {
cout << get7num(2007) << endl;
return 0;
}