题目描述
求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。
考察点:数学思维,发散思维。
思路1:参考讨论区,暴力破解。把所有数字转成字符串,再进行字符串单个查找,复杂度较高但是可行。
class Solution {
public:
int NumberOf1Between1AndN_Solution(int n)
{
int count = 0;
string s;
for (int i = 1; i <= n; i++)
s += to_string(i);
for (int i = 0; i < s.size(); i++)
if (s[i] == '1')
count++;
return count;
}
};
思路2:分别判断一个数字有多少个1,进行循环累加。复杂度为O(nlogn) 复杂度较高。
class Solution {
public:
int numOf1(unsigned int num)//计算一个数字里面含有几位1,分位判断
{
int number = 0;
while (num)
{
if (num % 10 == 1)
number++;
num = num / 10;
}
return number;
}
int NumberOf1Between1AndN_Solution(int n)
{
int count = 0;
for (unsigned int i = 1; i <= n; i++)//开始遍历
{
count += numOf1(i);
}
return count;
}
};
思路3:数字规律总结。参考牛客评论区,一位一位的分析1出现的次数。
假设N=abcde,都是十进制的数字。如果计算百位上的数字,受到三方面因素。百位数字,百位之前的数字,百位之后的数字。
1.如果百位上是0的话,那么出现1的次数由百位之前的数字决定。比如15012,百位上出现1的情况是(00)100-199,(0)1100-1199,..10100-10199...14100-14199,从0到14,总共是15个,每段对应的是100个数。那就是15*100。
2.如果百位上是1的话,那么出现1的次数由百位之前的数字和百位之后的数字决定,比如15112,除了上面分析的那些(00)100-199,(0)1100-1199... 14100-14199这15*100个数之外,还多了15100-15112,这些是113个数字,也就是百位之后的数字+1.
3.如果百位上的数字大于1的话,那么出现1的次数由百位之前的数字决定,比如15212,那么除了上面分析的那些(00)100-199,(0)1100-1199... 14100-14199这15*100个数之外,还多了15100-15199,相当于是(15+1)*100个数字。
class Solution {
public:
int NumberOf1Between1AndN_Solution(int n)
{
int count = 0;//1的个数
int i = 1; //当前位数,从个位开始遍历
int current = 0,after = 0, before = 0;//记录三个位置的值
while ((n / i) != 0)
{
current = (n / i) % 10;//,先处理n,再得到当前位。
before = n / (i * 10);//整除i*10,得到的是高位数字
after = n - (n / i) * i;//得到低位数字
if (current == 0)
{
count += before * i;
}
else if (current == 1)
{
count += before * i + after + 1;
}
else
count += (before + 1) * i;
i = i * 10;//i往前进位
}
return count;
}
};