本文最后更新于:2020年6月29日 晚上
题目描述:
求出1
13的整数中1出现的次数,并算出1001300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数。
实现如下:
//方法一
//将所有的数遍历一次,对每一个数的每一位再进行是否为1的判断
//时间复杂度为O(n*logn)
class Solution
{
private:
int NumberOf1(unsigned int n)
{
int number = 0;
while(n)//对此数字的每一位都进行判断
{
if(n % 10 == 1)//模10取余,判断是否为1
number++;
n = n / 10;//将最后一位舍弃
}
return number;
}
public:
int NumberOf1Between1AndN(unsigned int n)
{
int number = 0;//计数器
for(unsigned int i = 1; i <= n; ++i)//循环遍历所有的数
number += NumberOf1(i);
return number;
}
};
//方法二
//时间复杂度为O(logn)
class Solution
{
private:
static int PowerBase10(unsigned int num)//计算num与10次方的关系
{
int res = 1;
for (unsigned i = 0; i < num; ++i)
res *= 10;
return res;
}
static int NumberOf1(const char* str)
{
//防御性动作,判断字符串是否存在、第一个数字是否合法、字符串是否为NULL
if (!str || *str < '0' || *str > '9' || *str == '\0')
return 0;
int first = *str - '0';//取数字的最高位,将其转化为int
unsigned int length = static_cast<unsigned int>(strlen(str));//计算数字的位数,将其转化为unsigned int
if (length == 1 && first == 0)//如果是一位数且值为0,则直接返回0
return 0;
if (length == 1 && first > 0)//如果是一位数且值大于0,则1只出现1次,直接返回1
return 1;
int numFirstDigit = 0;
if (first > 1)//如果第一位数大于1,则计算数字与10的次方关系
numFirstDigit = PowerBase10(length - 1);
else if (first == 1)//如果第一位数等于1,则1出现的次数为从最高位为1到最大值的差值再加一
numFirstDigit = atoi(str + 1) + 1;
int numOtherDigits = first*(length - 1)*PowerBase10(length - 2);//计算次高位开始的数出现1的次数
int numRecursive = NumberOf1(str + 1);//递归计算从1开始到此数去掉最高位的数出现1的次数
return numFirstDigit + numOtherDigits + numRecursive;//返回之和
}
public:
int NumberOf1Between1AndN_Solution(int n)
{
if (n <= 0)//防御性动作
return 0;
char str[100];
sprintf(str, "%d", n);//将数字转化为字符串形式
return NumberOf1(str);
}
};
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!