劍指Offer(從 1 到 N 中 1 出現的次數)java實現

劍指offer上有一題:從1到N中1出現的次數,

比如N 爲12時,出現1的數字有1,10,11,12,那麼1總共出現5次。

思路:

使用遞歸思想,先考慮普通輸入N = 345,從1 -- 345可以分拆爲1 -- 45和46 -- 345(可以認爲是分分治思想)

分別求1 -- 45 和 46 -- 345中1出現的次數

  • 對1 -- 45也可以採用上述方法進行拆分爲1 -- 5和6 -- 45,這就是遞歸的部分
  • 對46--345這部分,我們需要知道有多個1: 

            1、首先關注345最高位3,因爲大於1,所以存在100--199 屬於46--345,也就是有10^(n - 1)個1(n爲345的位數)。

            2、對於345,因爲first > 1(first爲最高位數值),這樣按照上一步來計算。當first == 1時,最高位爲1的出現次數從100--145,爲46次,也就是非最高位數值+1。

            3、然後非最高位也可能存在1,如x1x,xx1,對x1x,最高位的x可以取1,2,3,個位的x可以取0--9,所以有3 * (10^1)種,同理xx1也有3*(10^1)種。所以非最高位存在1的總數爲 2 * 3 *(10^1)個,抽象爲(n - 1)*first *(10 ^(n - 2)),n爲345的位數。

             4、求完46 -- 345中1的個數,然後求1--45中1的個數,這是就是遞歸了,1---45可以拆分爲1--5和6--45,然後6--45執行上述的計算,1--5繼續遞歸。

             5、遞歸結束的條件是N的位數n == 1,這時候需要判斷這個傳入遞歸函數的N,if(N >= 1)return 1; if(N == 0)return 0;

源代碼:

public static int countDigitOne(int n) {
    if(n < 0)
        return 0;     //異常處理
    char[] ch = String.valueOf(n).toCharArray();
    return numOfOne(ch, 0);
}

private static int numOfOne(char[] ch, int index) {
     int first = ch[index] - '0';                //求取當下最高位的數值
     if(ch.length - index == 1 && first == 0)    // 遞歸條件判斷,輸入值是否爲1位且爲0
         return 0;
     if(ch.length - index == 1 && first >= 1)    //輸入值是否爲1位且大於等於1
         return 1;
     int numOtherOne = 0;
     if(first > 1)                             //求取最高位爲1的數字出現次數
         numOtherOne = power(ch.length - index - 1);
   
        
     if(first == 1)                             //求取最高位爲1的數字出現次數
         numOtherOne = power1(ch, index);
     int numLowOne = first * (ch.length - index - 1) * power(ch.length - index - 2); //求取非最高位爲1的數字出現次數
     int numRecurive = numOfOne(ch, index + 1);      //遞歸
     return numOtherOne + numLowOne + numRecurive;
}

private static int power(int n) {  //求取10^n
     int m = 1;
     for(int i = 0; i < n; i++)
         m *= 10;
     return m;
}

private static int power1(char[] ch, int index) {  //求取子字符數組的數值
     String s = String.valueOf(ch).substring(index + 1);
     return Integer.valueOf(s) + 1;
}

複雜度分析:

  • 時間複雜度:O(log(N))  

每一次遞歸的時間複雜度爲O(1),一個數字N有log(N)位,所以遞歸深度爲log(N)

總的時間複雜度O(log(N))。

  • 空間複雜度:需要創建一個字符數組來存放數字N的log(N)位。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章