题目描述
求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。
直观的解法:累加1到n之间的每个数中1出现的个数(每次求除以10的余数,除以10再求)。数n有logn位。
时间复杂度O(nlogn)
class Solution {
public:
int NumberOf1Between1AndN_Solution(int n)
{
int number = 0;
for(int i = 1; i <= n; i++)
{
number += NumberOf1(i);
}
return number;
}
int NumberOf1(int n)
{
int number = 0;
while(n)
{
if(n % 10 == 1)
number++;
n /= 10;
}
return number;
}
};
用一个大一点的数字21345作为例子来分析其中的数字规律。分成两段:1~1345,1346~21345。
先分析1346~21345段。最高位为1的情况有多少种呢?10000~19999(10^4个)。如果n的最高位为1,则只有10000~11345(除去最高位数字再加1种)。
再分析剩下4位中某位为1的情况:这里再将1346~21345分成两段1346~11345,11346~21345。每一段1的个数是:4*10^3 (其他3位可取0~9共10位数字中的任何一个)。
接下来递归分析1~1346中1个个数。
总递归次数等于n的位数。
时间复杂度O(logn)(底数是10)
#include<cstdio>
class Solution {
public:
int NumberOf1Between1AndN_Solution(int n)
{
if(n <= 0) return 0;
char strN[50];
sprintf(strN, "%d", n);
return NumberOf1(strN);
}
int NumberOf1(const char* strN)
{
if(!strN || *strN < '0' || *strN > '9' || *strN == '\0')
return 0;
int first = *strN - '0';
unsigned int length = static_cast<unsigned int>(strlen(strN));
if(length == 1 && first == 0)
return 0;
if(length == 1 && first > 0)
return 1;
int numFirstDigit = 0;
if(first > 1)
numFirstDigit = PowerBase10(length-1);
else if(first == 1)
numFirstDigit = atoi(strN+1) + 1;
int numOtherDigits = first * (length - 1) * PowerBase10(length - 2);
int numRecursive = NumberOf1(strN + 1);
return (numFirstDigit + numOtherDigits + numRecursive);
}
int PowerBase10(unsigned int n)
{
int result = 1;
for(unsigned int i = 0; i < n; i++)
result *= 10;
return result;
}
};
其他人的思路 1
其他人的思路 2
public int NumberOfXBetween1AndN_Solution(int n,int x) {
if(n<0||x<1||x>9)
return 0;
int high,low,curr,tmp,i = 1;
high = n;
int total = 0;
while(high!=0){
high = n/(int)Math.pow(10, i);// 获取第i位的高位
tmp = n%(int)Math.pow(10, i);
curr = tmp/(int)Math.pow(10, i-1);// 获取第i位
low = tmp%(int)Math.pow(10, i-1);// 获取第i位的低位
if(curr==x){
total+= high*(int)Math.pow(10, i-1)+low+1;
}else if(curr<x){
total+=high*(int)Math.pow(10, i-1);
}else{
total+=(high+1)*(int)Math.pow(10, i-1);
}
i++;
}
return total;
}