從1到n的所有數相關問題

在學習過程中,遇到了兩道題目。卡了自己一段時間,通過查閱資料,已經AC。下面貼一下這兩道題目。

這道題是計算1~n的所有數字中,1出現的個數。這道題目是劍指offer中比較難的一道題目。首先考慮在計算過程中,有一定規律,但是在具體的coding過程中,總不能加各種if條件句判斷吧。所以通過查資料學習了這樣一種解決該問題的方法:

例如,n=abcde。首先,將n切分開來存放到數組之中。之後進行具體的邏輯判斷。以具體數值c爲例,需要考慮他的高位和低位情況,高位即ab的情況,低位即de的情況。

先不考慮c的具體值,先考慮c的高位的一個情況。00~ab-1,因爲當考慮的ab時,需要看c的情況,所以先判斷00~ab的一個情況,這時候其實可以直接算出來至少100種(00~99)之後需要考慮c的情況,如果c=0,則不考慮,如果c=1,則需要加上de+1(00~de)。如果c>1.則直接加100(00~99)。具體邏輯就是這樣

/***
     * 設數字爲abcde,當前位數爲c位,
       c位1的個數即爲高位個數+低位個數
       高位範圍爲 00 ~ ab-1 :
       有 ab*100 個(因爲c在百位)
       低位分爲三種情況:
       c = 0 ,有 0 個
       c = 1 ,有 de + 1 個
       c > 1 , 有 100 個 (因爲c在百位)
       依次遍歷每一位數相加,即爲總共1的個數
     * @param n
     * @return
     */
    public static int numberOf1Between1AndN_Solution(int n) {
        if(n==0) {
            return 0;
        }
        ArrayList<Integer>list=new ArrayList<>();
        while(n!=0){
            list.add(n%10);
            n=n/10;
        }
        int size=list.size();

        int res=0;
        for (int i=size-1;i>=0;i--){
            int left=0,right=0,t=1;
            //處理第i位之前的數
            for (int j=size-1;j>i;j--){
                left=left*10+list.get(j);
            }
            //處理第i位之後的數
            for (int j=i-1;j>=0;j--) {
                right=right*10+list.get(j);
                t=t*10;
            }
            //00~ab-1的情況
            res+=left*t;
            if (list.get(i)==1) {
                res += right + 1;
            }else if (list.get(i)>1){
                res+=t;
            }
        }
        return res;
    }

 

第二道題目計算第n位數的具體數值。這道題目數學的味道比較濃厚。需要我們找一找固定的規律。

首先1位數有10中情況,2位數有90中情況,3位數有900種情況。。。

其次,我們需要根據n的具體值,來判斷第n位數所在的值是多少位數所組成。所以,需要根據具體的規律算出來。例如,確定好n在3位數中的某一個值的某一位上。需要對ceil(n/3)確定在第幾個數字上。之後需要n對i取模,計算在該值的第幾位上。

我們需要設置一個初始變量 i代表是幾位數的情況,s代表i位數有多少個,base代表i位數的起始值。

需要注意的是,爲了便於計算,我們規定起始值從1開始,這樣1位數有9種情況,2位數有90種情況,3位數有900中情況。。。便於計算。最終在計算第幾個數時,減去1即可。

public int digitAtIndex(int n) {
        if (n==0) {
            return 0;
        }
        /***
         * i代表是幾位數,base代表i位數時的起始值,s代表i位數的個數
         */
        long i=1,s=9,base=1;
        while (n>i*s){
            n= (int) (n-i*s);
            i+=1;
            base*=10;
            s=s*10;
        }
        /**
         * 剩下的n代表第i位後面的情況,number用於計算剩下的n應該在base的什麼位置,n/i需要向上取整
         * 這裏最後減1是因爲需要考慮最開始的0.
         * r用於計算n具體的位置。
         */
        int number= (int) (base+(n+i-1)/i-1);
        int r= (int) (n%i==0?i:n%i);
        for (int j=0;j<i-r;j++){
            number/=10;
        }
        return number%10;
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章