剑指offer题目31:从1到n整数中1出现的次数
题目描述
输入一个整数n,求从1到n这n个整数的十进制表示中1出现的次数,例如输入13,1~13中包含1的数字有1、10、11、12、13因此共出现6次。
解答思路
这道题目对我来说也挺难的,需要做的就是画出例子来分析。
如数字21345。
我们先分别统计每位出现1的次数然后累加起来。
个位数
我们注意到每循环10次数,必定出现1次1,如0 - 9,出现了1, 再如10-19,11里的个位也出现了1。
那么我们可以得出如下公式:
sum = n / 10 * 1;
但是注意到最后的的区间一般是不完整的,例如数字23,有0-9,10-19,20-23。最后余3,如果这个数是大于等于1的话,也是可以算是1次的。
k = n % 10;
sum = n / 10 * 1 + (k >= 1 ? 1 : 0);
十位数
同理分析,每循环100次,必定出现10次,如10-19,110-119。
sum = n / 100 * 10;
同理注意到可最后的区间,如数字115,偏移量15,有区间110-115。则出现1的次数是15-10+1=6次。如数字119,出现1的次数是10。
k = n % 100;
if(k >= 19)
offset = 10;
else if (k >= 10)
offset = k - 10;
百位数
同理分析,每循环1000次,必定出现100次,如100-199,1100-1199,2100-2199。
sum = n / 1000 * 100;
同理注意到可最后的区间,如数字1115,有区间1100-1115。则出现1的次数是1115-1100+1=16次。
k = n % 1000;
if(k >= 199)
offset = 100;
else if (k >= 100)
offset = k - 100;
实现代码
class Solution {
public:
int NumberOf1Between1AndN_Solution(int n)
{
int sum = 0;
for (int i = 1; i <= n; i*= 10)
{
int diviver = i * 10;
sum += n / diviver * i;
// 计算剩余阶梯的
int k = n % diviver;
if(k >= i * 2 - 1) {
sum += i;
} else if(k >= i) {
sum += k - i + 1;
}
}
return sum;
}
};
作者:大傻逼
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

浙公网安备 33010602011771号