剑指offer43 1~n整数中1出现的次数

首先暴力解法,遍历1~n,单独写个函数统计每个数字中1出现的次数,最后相加即可。

数字n有logn位,故时间复杂度O(nlogn)。

但其实这个问题是有数学规律的。

我们也以剑指offer上的数 21345为例,来看看有什么规律。

首先,10000~19999,万位的1有10000个。也即0~21345万位的1有10000个。

然后我们把0~21345分为0~1345,1346~11345,11346~21345三段。

后两段中,后四位出现1的次数应该为$2*C_4^1*10^3=8000$。因为这个可以看作一个排列问题:四位数字中出现1的排列。然后对于重复的数字,比如1101,本应该去重只计算1次,但是由于我们算的是出现1的次数,1101出现3次,而我们在千、百、个位各计一次是正好的。所以问题转化为:四位分别是1时,其他位随便排列,记一次。

如果还不理解,可以看2位数的情况,答案应为2*10 = 20。

10~109中,忽略百位的1,出现1的有:

10,11,12,13,14,15,16,17,18,19,

21,31,41,51,61,71,81,91,101  共20个1.

第一行只计十位的1,第二行只计个位的1的话:

10,11,12,13,14,15,16,17,18,19,

11,21,31,41,51,61,71,81,91,101  正好20个数。

然后0~1345可以递归使用以上方法。

public class Solution {
    public int NumberOf1Between1AndN_Solution(int n) {
        if(n<=0) return 0;
        int temp = n;
        int ndigit = 0;
        while(temp!=0){
            temp/=10;
            ndigit++;
        }
        return getNumber(n,ndigit);
    }
    private int getNumber(int n,int ndigit){
        if(ndigit<1) return 0;
        if(n==0) return 0;
        int firstDigit = n/(int)Math.pow(10,ndigit-1);
        int count = 0;
        if(firstDigit>1){
            count+=(int)Math.pow(10,ndigit-1);
        }else{//firstDigit==1
            count+=n%(int)Math.pow(10,ndigit-1)+1;
        }
        if(ndigit>1) count+=firstDigit*(ndigit-1)*(int)Math.pow(10,ndigit-2);
        return count+getNumber(n%(int)Math.pow(10,ndigit-1),ndigit-1);
    }
}

运行时间:29ms

占用内存:9244k

 

# -*- coding:utf-8 -*-
class Solution:
    def NumberOf1Between1AndN_Solution(self, n):
        # write code here
        if n<1:
            return 0
        digit = 0
        temp = n 
        while temp>0:
            temp=temp//10
            digit+=1
        return self.helper(n,digit)
    
    def helper(self,n,digit):
        if digit<=0 or n==0:
            return 0
        ans = 0 
        firstDigit = n//(10**(digit-1))
        if firstDigit==1:
            ans = n%(10**(digit-1))+1
        else:
            ans = 10**(digit-1)
        ans += firstDigit*(digit-1)*(10**(digit-2))
        return ans+self.helper(n%(10**(digit-1)),digit-1)

运行时间:24ms

占用内存:5860k

posted @ 2019-02-28 14:45  大胖子球花  阅读(127)  评论(0)    收藏  举报