在从1到n的正数中1出现的次数

来源:互联网 发布:vb.net 正则表达式 编辑:程序博客网 时间:2024/06/15 00:49

题目:输入一个整数n,求从1nn个整数的十进制表示中1出现的次数。

例如输入12,从112这些整数中包含1的数字有11011121一共出现了5次。

最简单思路,就是从1-n一个刚数字进行判断然后计数即可,

int NumberOf1BeforeBetween1AndN_Solution1(unsigned int n){int number = 0;// Find the number of 1 in each integer between 1 and nfor(unsigned int i = 1; i <= n; ++ i)number += NumberOf1(i);return number;}int NumberOf1(unsigned int n){int number = 0;while(n){if(n % 10 == 1)number ++;n = n / 10;}return number;}

这个思路有一个非常明显的缺点就是每个数字都要计算1在该数字中出现的次数,因此时间复杂度是O(n)。当输入的n非常大的时候,需要大量的计算,运算效率很低。这里引入新的思路,以n=21345为例,可以分成两部分1-1345和1346-21345,先分析1236-21345这一部分20000个数字,1-1345迭代即可。

对于1236-21345分析1出现的次数,可以分两种情况

a 1在最高位(万),一共在10000-19999中出现过,一共10^4次,当然这是在这个最高位数字2大于1的情况下,如 最高位原数字就是等于1,如11345则此时统计最高位1出现次数很明显就只有1345+1次

b 1在其他为(后四位),选取一位为1,有len-1=4种选法,每种指定1后,剩下3位有10^3种情况,再考虑最高位后1出现此时最高位数字2×4×10^3。

剩下的对1-1345类似分析即可。

代码:

int powerbase10(int n){int res=1;for(int i=0;i<n;i++)    res*=10;return res;}//10^nint numberof1(string str){if(str.size()<1)return 0;int first=str[0]-'0';unsigned int len=static_cast<unsigned int>(str.size());if(len==1&&first==0)return 0;if(len==1&&first>0){return 1;                    }int num_first=0;int num_other=first*(len-1)*powerbase10(len-2);int numrecursive=numberof1(str.substr(1));if(first>1)num_first=powerbase10(len-1);else if(first==1)num_first=atoi(str.substr(1).c_str())+1;return num_first+num_other+numrecursive;}


原创粉丝点击