我是靠谱客的博主 大气朋友,最近开发中收集的这篇文章主要介绍剑指offer——面试题32:从1到n整数中1出现的次数剑指offer——面试题32:从1到n整数中1出现的次数,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

剑指offer——面试题32:从1到n整数中1出现的次数

Solution1:

最容易想到的方法:

class Solution {
public:
int NumberOf1Between1AndN_Solution(int n){
int res = 0;
for(int i = 1; i <= n; i++)
res += NumOfOne(i);
return res;
}
int NumOfOne(int n){
int temp = 0, yushu = 0;
while (n != 0) {
yushu = n%10;
if (yushu == 1)
temp++;
n /= 10;
}
return temp;
}
};

Solution2:

利用字符串查找的方法对solution1稍加修改
主要学习在string对象中利用count函数统计某个字符出现个数的用法。

class Solution {
public:
int NumberOf1Between1AndN_Solution(int n) {
int res = 0;
for (int i = 1; i <= n; i++)
res += NumOfOne(i);
return res;
}
int NumOfOne(int n) {
string str = to_string(n);
int nums = count(str.begin(), str.end(), '1');
return nums;
}
};

Solution3:

参考网址:http://blog.csdn.net/yi_afly/article/details/52012593。把大神的博客粘贴在这里。。
大神的思路就是厉害啊!
在看大神的解题思路前说一下自己的感想:
看完这个思路后很容易就产生某些数如11,111等会被重复统计的情况。首先要看清题目要求:是统计从1到n整数中1出现的次数,而非统计含有1的整数有多少个。该算法的思想是依次统计1在个、十、百、千等位置上的出现次数。11的确会被统计两次,111也会被统计三次。拿111为例:当111被第一次统计时,是在统计个位上出现的一次1;当111被第二次统计时,是在统计十位上出现的一次1;当111被第三次统计时,是在统计百位上出现的一次1,故而对于1出现的总次数而言,并不存在重复计数的情况。
试想如果题目是:统计从1到n整数中含有1的整数,应该怎么做呢?我的第一想法是把所有的数字变为string对象,然后查找字符‘1’,理论上复杂度是 O(n) O ( n ) 。不知道有木有更好的算法,有的话不吝赐教~
解题思路
考虑将n的十进制的每一位单独拿出讨论,每一位的值记为weight。
1) 个位
从1到n,每增加1,weight就会加1,当weight加到9时,再加1又会回到0重新开始。那么weight从0-9的这种周期会出现多少次呢?这取决于n的高位是多少,看图:
这里写图片描述
以534为例,在从1增长到n的过程中,534的个位从0-9变化了53次,记为round。每一轮变化中,1在个位出现一次,所以一共出现了53次。
再来看weight的值。weight为4,大于0,说明第54轮变化是从0-4,1又出现了1次。我们记1出现的次数为count,所以:
count = round+1 = 53 + 1 = 54

如果此时weight为0(n=530),说明第54轮到0就停止了,那么:
count = round = 53
2) 十位
对于10位来说,其0-9周期的出现次数与个位的统计方式是相同的,见图:
这里写图片描述
不同点在于:从1到n,每增加10,十位的weight才会增加1,所以,一轮0-9周期内,1会出现10次。即round*10。
再来看weight的值。当此时weight为3,大于1,说明第6轮出现了10次1,则:
count = round*10+10 = 5*10+10 = 60

如果此时weight的值等于0(n=504),说明第6轮到0就停止了,所以:
count = round*10+0 = 5*10 = 50

如果此时weight的值等于1(n=514),那么第6轮中1出现了多少次呢?很明显,这与个位数的值有关,个位数为k,第6轮中1就出现了k+1次(0至k,共k+1个数)。我们记个位数为former,则:
count = round*10+(former +1)= 5*10+(4+1) = 55
3) 更高位
更高位的计算方式其实与十位是一致的,不再阐述。

4) 总结
将n的各个位分为两类:个位与其它位。
对个位来说:

若个位大于0,1出现的次数为round*1+1
若个位等于0,1出现的次数为round*1
对其它位来说,记每一位的权值为base,位值为weight,该位之前的数是former,举例如图:
这里写图片描述
则:
若weight为0,则1出现次数为round*base
若weight为1,则1出现次数为round*base+former+1
若weight大于1,则1出现次数为rount*base+base
比如:

534 = (个位1出现次数)+(十位1出现次数)+(百位1出现次数)=(53*1+1)+(5*10+10)+(0*100+100)= 214
530 = (53*1)+(5*10+10)+(0*100+100) = 213
504 = (50*1+1)+(5*10)+(0*100+100) = 201
514 = (51*1+1)+(5*10+4+1)+(0*100+100) = 207
10 = (1*1)+(0*10+0+1) = 2
完整代码

class Solution {
public:
int NumberOf1Between1AndN_Solution(int n) {
if (n < 1) return 0;
int count = 0, base = 1, round = n;
while (round > 0) {
int weight = round % 10;
round /= 10;
count += round * base;
if (weight == 1)
count += (n % base) + 1;
else if (weight > 1)
count += base;
base *= 10;
}
return count;
}
};

时间复杂度分析
由分析思路或者代码都可以看出,while循环的次数就是n的位数, logn l o g n (以10为底),而循环体内执行的操作都是有限次的,所以时间复杂度为 O(logn) O ( l o g n )
真是一个好思路啊~

最后

以上就是大气朋友为你收集整理的剑指offer——面试题32:从1到n整数中1出现的次数剑指offer——面试题32:从1到n整数中1出现的次数的全部内容,希望文章能够帮你解决剑指offer——面试题32:从1到n整数中1出现的次数剑指offer——面试题32:从1到n整数中1出现的次数所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(42)

评论列表共有 0 条评论

立即
投稿
返回
顶部