由于平时自己专心在搞项目,对于算法之类的没有花太多心思。毕业临近,为了找工作,开始在leetcode上刷题。刚刚在做Number of Digit One ,并百度了一下网上的解法,发现自己的解法跟别人的不太一样,所以拿出来跟大家分享下。
一、题目翻译过来大概是这么个意思: 给定一个十进制正整数N,写下从1开始,到N的所有整数,然后数一下其中出现的所有“1”的个数。
1.解法1,参照剑指offer中面试题32.
2.解法2.参照博客链接:http://blog.youkuaiyun.com/zcsylj/article/details/6393315
3.我的解法.
二、算法思路:
a.首先将一个数拆成最高位基数幂以下部分+最高位基数幂以上部分的形式,如323拆成0~300和300~323
b.要计算N中1的个数,大致分为3步:1.求取高位中1出现的次数,若最高位为1,则最高位1的重复次数为去掉最高位数加1,假设N=123,则最高位1的重复次数为23+1=24;若最高位不为1,则最高位出现次数为最高位基数幂,假设N=323,则最高位1的重复次数为100;2.求取最高位非1部分对个数1的影响,假设N=323,则可以拆成求3个0~99区间中的个数和,至于0~99可以使用排列组合很容易计算得到;3.前面两步实现对最高位基数幂以下部分计算,对于最高位基数幂以上部分,由于最高位已经不再影响1的个数,所以可以去掉最高位部分递归求取,如对于300~323,只要求N=23部分的1个数即可。
c.递归结束条件是只剩个位数。
三、代码实现:
//计算0~N中1的个数
int countDigitOne(int n) {
//若为个位数,则结束递归
if(n<10)
{
if(n>=1)
return 1;
else
return 0;
}
//计算最高位的幂
int base=1,len=0;
int tmp=n;
while(tmp=tmp/10)
{
base*=10;
len++;
}
//返回最高位中影响1的重复次数和递归部分
if((n/base)>1)
return base+countDigitOne(n%base)+(n/base)*digitOne(len);
else
return n-base+countDigitOne(n%base)+digitOne(len)+1;
}
//计算0~9...9部分中1的个数
int digitOne(int n)
{
if(n==1)
return 1;
int tmp=n-1,count=1;
while(tmp)
{
count*=10;
--tmp;
}
return count*n;
}
四、算法性能
其中旁边黄色的是其他方法用C++跑的性能,可以看出来使用这种方法速度还是很快的。