劍指Offer-31.整數中1出現的次數(從1到n整數中1出現的次數)(C++/Java)

題目:

求出1~13的整數中1出現的次數,並算出100~1300的整數中1出現的次數?爲此他特別數了一下1~13中包含1的數字有一、十、十一、十二、13所以共出現6次,可是對於後面問題他就沒轍了。ACMer但願大家幫幫他,並把問題更加廣泛化,能夠很快的求出任意非負整數區間中1出現的次數(從1 到 n 中1出現的次數)。函數

分析:

能夠編寫一個判斷一個數字有多少個1的函數,而後遍歷1-n依次調用統計函數,最後求和便可,不過這樣時間複雜度有些多。spa

咱們能夠按數字的位數來依次統計1出現的個數,例如21345這個數,咱們先看1346-21345區間1出現的個數。code

先統計萬位出現1的個數,咱們知道,10000-19999,萬位共出現了10000次,也就是10^4個1,考慮一下特殊狀況,若是是12345這樣的數,實際上萬位出現1的個數就等於萬位後面的數字加1,也就是2345+1=2346次。blog

再來計算後面,也就是其他4位1出現的次數1346-21345能夠拆成兩部分來看,一部分是1346-11345,每一段剩下的4位數字中,選擇1位是1,其他三位能夠選擇0-9,也就是出現了10^3次,共4位因此也就是4*10^3次,同理剩下的部分11346-21345也是4*10^3次。遞歸

而剩下的1-1345區間出現1的個數能夠經過遞歸求得。io

程序:

C++class

class Solution {
public:
    int NumberOf1Between1AndN_Solution(int n)
    {
        int length = 0;
        int num = n;
        while(num){
            num /= 10;
            length++;
        }
        return helper(n, length);
    }
    int helper(int num, int length){
        if(length == 0 || num <= 0)
            return 0;
        int numfirst = 0;
        int first = num / pow(length-1);
        if(length == 1 && first > 0)
            return 1;
        if(first > 1){
            numfirst = pow(length-1);
        }
        if(first == 1){
            numfirst = num - pow(length-1) + 1;
        }
        int numother = first * (length - 1) * pow(length-2);
        return numfirst + numother + helper(num - first*pow(length-1), length-1);
    }
    int pow(int num){
        int res = 1;
        for(int i = 0; i < num; ++i)
            res *= 10;
        return res;
    }
};

Java遍歷

public class Solution {
    public int NumberOf1Between1AndN_Solution(int n) {
        if(n <= 0)
            return 0;
        int res = 0;
        while(n != 0){
            res += helper(n);
            n--;
        }
        return res;
    }
    public int helper(int n){
        int count = 0;
        while(n != 0){
            if(n % 10 == 1)
                count++;
            n /= 10;
        }
        return count;
    }
}
相關文章
相關標籤/搜索