#include <iostream>
#include <stdio.h>
using namespace std;
/*
问题:编写一个方法,数出0到n(含)中数字2出现了几次
分析:剑指offer中,题目是数出0到n中数字1出现了几次。应该是同一个类型
记得当时是用递归做的。
暴力破解:就是遍历0到n,对每个数字i,获取其每一位上的值,统计是否含有2,假设平均每个数字有k位,时间复杂度就是O(n*k)。
另一种是采用递归的方式,统计出每种模式下,比如n有k位,那么计算所有k-1位的上的2的个数,而k-1位上的2的个数
以一个简单的例子讲解:十位数是个位数前面加上一个1~9,比如10~99,是对个位数0~9中每个前面分别加上1~9
注意百位数有区别,比如:100~999,是对所有十位数10~99前面分别加上1~9,这样还会漏掉:100~109,所以要把百位数最小值100~添加后的最小百位数110-1进行累加
输入:
1000(n) 1(统计的值)
21345 1
1000 2
21345 2
输出:
301
18821
300
9821
关键:
1 以统计1到n中1出现的次数为例分析(与统计1到n中2出现的次数是一样的题目)
以21345为例进行拆分,拆分成低位部分:1~1345和高位部分1346~21345,
设整数strN,最高位为第i位,值为k
1】先统计整数strN仅包含最高位部分: 发现如果最高位k=1(例如11345),则1的个数等于后面低位部分:1345+1,即为 atoi(strN+1) + 1
k>1(例如21345),则1的个数等于: k*10^(i-1)
2】统计不包含最高位的低位部分中,1的出现次数,发现1出现的(例如21345)的次数 = k * 10^(i-2),然后遍历剩余i-1个低位中,设置任意低位为1
则总的次数 =(i-1)* k * 10^(i-2)
3】递归对低位部分进行处理,记总次数为num
1的个数= 第i位为1则为(剩余位值+1) 或 第i位不为1则为(第i位的值 * 10的(i-1)次方) + 除高位外次最高位中1的个数(高位的值 * 10的(i-2)次方 * (i-1)) + 递归得到低位中含1的个数
2
int countNumber(const char* strN , int searchValue)
{
if(NULL == strN || (*strN) < '0' || (*strN) > '9')
{
return 0;
}
//获取长度
int length = strlen(strN);
int firstDigit = *strN - '0';
//如果是0
if(1 == length && firstDigit < searchValue)
{
return 0;
}
if(1 == length && firstDigit >= searchValue)
{
return 1;
}
将数n分成三部分:假设数n有i位,则
分成:低位部分(数n的第1位到第i-1位),高位部分
比如21345分成:1~1345,1346~21345(不含最高位的低位部分)
1的个数= 第i位为1则为(剩余位值+1) 或 第i位不为1则为(第i位的值 * 10的(i-1)次方) + 除高位外次最高位中1的个数(高位的值 * 10的(i-2)次方 * (i-1)) + 递归得到低位中含1的个数
int numberHigh = 0;
int numberOther = 0;
int numberRecursive = 0;
//注意这里是大于1,而不是不等于1
if(firstDigit > searchValue)
{
//这里不要乘以个数firstDigit
numberHigh = powerBase10(length - 1);
}
else if(firstDigit == searchValue)
{
numberHigh = atoi(strN + 1) + 1;
}
numberOther = firstDigit * (length - 1) * powerBase10(length - 2); //为什么要乘以length-1,就是说从剩余length-1位中任选一位为1,first * power(lenght-2)决定了除高位剩余位的元素数量
//numberOther = firstDigit * powerBase10(length - 2);//
numberRecursive = countNumber(strN + 1, searchValue);
int result = numberHigh + numberOther + numberRecursive;
return result;
}
*/
const int MAXSIZE = 1024;
int powerBase10(int times)
{
int result = 1;
for(int i = 0 ; i < times ; i++)
{
result *= 10;
}
return result;
}
int countNumber(const char* strN , int searchValue)
{
if(NULL == strN || (*strN) < '0' || (*strN) > '9')
{
return 0;
}
//获取长度
int length = strlen(strN);
int firstDigit = *strN - '0';
//如果是0
if(1 == length && firstDigit < searchValue)
{
return 0;
}
if(1 == length && firstDigit >= searchValue)
{
return 1;
}
/*
将数n分成三部分:假设数n有i位,则
分成:低位部分(数n的第1位到第i-1位),高位部分
比如21345分成:1~1345,1346~21345(不含最高位的低位部分)
1的个数= 第i位为1则为(剩余位值+1) 或 第i位不为1则为(第i位的值 * 10的(i-1)次方) + 除高位外次最高位中1的个数(高位的值 * 10的(i-2)次方 * (i-1)) + 递归得到低位中含1的个数
*/
int numberHigh = 0;
int numberOther = 0;
int numberRecursive = 0;
//注意这里是大于1,而不是不等于1
if(firstDigit > searchValue)
{
//这里不要乘以个数firstDigit
numberHigh = powerBase10(length - 1);
}
else if(firstDigit == searchValue)
{
numberHigh = atoi(strN + 1) + 1;
}
numberOther = firstDigit * (length - 1) * powerBase10(length - 2); //为什么要乘以length-1,就是说从剩余length-1位中任选一位为1,first * power(lenght-2)决定了除高位剩余位的元素数量
//numberOther = firstDigit * powerBase10(length - 2);//
numberRecursive = countNumber(strN + 1, searchValue);
int result = numberHigh + numberOther + numberRecursive;
return result;
}
//获取一个整数value上searchValue值得个数
int countValue(int value , int searchValue)
{
int result = 0;
int count = 0;
while(value)
{
result = value % 10;
if(result == searchValue)
{
count++;
}
value /= 10;
}
return count;
}
int count(int n , int value)
{
int sum = 0;
int result = 0;
for(int i = 1 ; i <= n ; i++)
{
result = countValue(i , value);
sum += result;
}
return sum;
}
void process()
{
char strN[MAXSIZE];
int searchValue = 1;
while(scanf("%s %d", strN , &searchValue))
//while(scanf("%s", strN))
{
int result = countNumber(strN , searchValue);
int n = atoi(strN);
int result2 = count(n , searchValue);
cout << result << endl;
//cout << result2 << endl;
memset(strN , 0 , sizeof(strN));
}
}
int main(int argc , char* argv[])
{
process();
getchar();
return 0;
}
程序员面试金典——解题总结: 9.18高难度题 18.4编写一个方法,数出0到n(含)中数字2出现了几次
最新推荐文章于 2022-11-23 10:43:05 发布