【Java】 劍指offer(62) 圓圈中最后剩下的數字


 

本文參考自《劍指offer》一書,代碼采用Java語言。

更多:《劍指Offer》Java實現合集  

題目

  0, 1, …, n-1這n個數字排成一個圓圈,從數字0開始每次從這個圓圈里刪除第m個數字。求出這個圓圈里剩下的最后一個數字。

思路

  方法一:采用鏈表來存放數據,每次對長度取余來實現循環

  將所有數字放入LinkedList鏈表中(LinkedList比ArrayList更適合增刪操作)。假設當前刪除的結點下標為removeIndex,則下一個要刪除的結點的下標為:(removeIndex+m-1)%list.size(),通過取余符號可以實現類型循環的操作。

  注:沒必要用循環鏈表,反而會更麻煩了。

  方法二:數學推導規律

  n個數字的圓圈,不斷刪除第m個數字,我們把最后剩下的數字記為f(n,m)

  n個數字中第一個被刪除的數字是(m-1)%n, 我們記作k,k=(m-1)%n

  那么剩下的n-1個數字就變成了:0,1,……k-1,k+1,……,n-1,我們把下一輪第一個數字排在最前面,並且將這個長度為n-1的數組映射到0~n-2。

  原始數字:k+1,……,   n-1,       0,    1,……k-1

  映射數字:0    ,……,n-k-2, n-k-1, n-k,……n-2

  把映射數字記為x,原始數字記為y,那么映射數字變回原始數字的公式為 y=(x+k+1)%n

  在映射數字中,n-1個數字,不斷刪除第m個數字,由定義可以知道,最后剩下的數字為f(n-1,m)。我們把它變回原始數字,由上一個公式可以得到最后剩下的原始數字是f(n-1,m)+k+1)%n,而這個數字就是也就是一開始我們標記為的f(n,m),所以可以推得遞歸公式如下:

          f(n,m) =f(n-1,m)+k+1)%n

  將k=(m-1)%n代入,化簡得到:

          f(n,m) =f(n-1,m)+m)%n

          f(1,m) = 0

  代碼中可以采用循環或者遞歸的方法實現該遞歸公式。時間復雜度為O(n),空間復雜度為O(1)

 

測試算例 

  1.功能測試(m大於/小於/等於n)

  2.特殊測試(n、m<=0)

  3.性能測試(n=4000,n=997)

 

Java代碼

//題目:0, 1, …, n-1這n個數字排成一個圓圈,從數字0開始每次從這個圓圈里
//刪除第m個數字。求出這個圓圈里剩下的最后一個數字。

public class LastNumberInCircle {
    /*
     * 方法一:采用推導出來的方法
     */
    public int LastRemaining_Solution(int n, int m) {
        if(n<1 || m<1)
            return -1; //出錯
        int last=0;
        for(int i=2;i<=n;i++){
            last=(last+m)% i;  //這里是i不是n!!!
        }
        return last;
    }
    
    /*
     * 方法二:采用鏈表來存放,每次對長度取余來實現循環
     */
    public int LastRemaining_Solution2(int n, int m) {
        if(n<1 || m<1)
            return -1; //出錯
        LinkedList<Integer> list = new LinkedList<Integer>();
        for(int i=0;i<n;i++)
            list.add(i);
        int removeIndex=0;
        while(list.size()>1){
            removeIndex=(removeIndex+m-1)%list.size();
            list.remove(removeIndex);
        }
        return list.getFirst();
    }
}

  

收獲

  1.對於下標循環一圈類似的問題,通過%可以很好地實現循環,而不需要我們自己構造循環鏈表;

  2.(a%n+b)%n=(a+b)%n

  3.盡量學會本題的數學方法,特別是要掌握好數字間映射的方法。

  4.公式法中,last=(last+m)% i;  //這里是i不是n!!!

 

更多:《劍指Offer》Java實現合集  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM