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

 

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

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

題目

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

思路

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

  將全部數字放入LinkedList鏈表中(LinkedList比ArrayList更適合增刪操做)。假設當前刪除的結點下標爲removeIndex,則下一個要刪除的結點的下標爲:(removeIndex+m-1)%list.size(),經過取餘符號能夠實現類型循環的操做。性能

  注:不必用循環鏈表,反而會更麻煩了。測試

  方法二:數學推導規律url

  n個數字的圓圈,不斷刪除第m個數字,咱們把最後剩下的數字記爲f(n,m)code

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

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

  原始數字: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實現合集 

相關文章
相關標籤/搜索