1. 程式人生 > >劍指Offer - 孩子們的遊戲(圓圈中最後剩下的數)(Java實現)

劍指Offer - 孩子們的遊戲(圓圈中最後剩下的數)(Java實現)

題目描述:

每年六一兒童節,牛客都會準備一些小禮物去看望孤兒院的小朋友,今年亦是如此。HF作為牛客的資深元老,自然也準備了一些小遊戲。其中,有個遊戲是這樣的:首先,讓小朋友們圍成一個大圈。然後,他隨機指定一個數m,讓編號為0的小朋友開始報數。每次喊到m-1的那個小朋友要出列唱首歌,然後可以在禮品箱中任意的挑選禮物,並且不再回到圈中,從他的下一個小朋友開始,繼續0…m-1報數…這樣下去…直到剩下最後一個小朋友,可以不用表演,並且拿到牛客名貴的“名偵探柯南”典藏版(名額有限哦!!_)。請你試著想下,哪個小朋友會得到這份禮品呢?(注:小朋友的編號是從0到n-1)

思路分析:
看到轉圈迴圈,首先就想到用迴圈連結串列來解決問題。
所以先建立一個節點類,然後根據小朋友的個數生成對應的節點數,並將他們首尾連線起來。
生成連結串列以後,根據題意來分析,對於每次點到的節點將會剔除出該迴圈連結串列,所以需要用兩個指標來記錄需要剔除的節點以及該節點的上一個節點pre,並將上一個節點的Next指標指向該節點的下一個節點,完成剔除工作。
以此類推,對於迴圈連結串列而言,迴圈終結的終點是對於最後一個剔除的節點,其前一個節點的next指標必然會指向自己,所以迴圈結束標誌就是pre.next = pre;
程式碼實現如下:

//先嚐試連結串列的方式來解決問題
//迴圈結束的標誌是當前節點的下一個指標指向自己
public class Solution {
    public int LastRemaining_Solution(int n, int m) {
        
        if( n < 1 || m < 1){
            return -1;
        }
        if(n==1){
            return 0;
        }
        //先形成一個迴圈連結串列
        LinkNode head = new LinkNode(0);
        LinkNode next = null;
        LinkNode cur = head;
        for(int i = 1 ; i < n ; i++ ){
            next = new LinkNode(i);
            cur.next = next;
            cur = next;
            if( i== n-1){
                next.next = head;
            }
        }
        //需兩個指標分別來記錄當前位置和前一個的位置,
        cur = head;
        LinkNode pre = next;
        while(pre.next != pre){
            int count = m;//計數器
            while(count-1 > 0){//當不符合條件時,節點依次往後推進。
                pre = cur;
                cur = cur.next;
                count--;
            }
            //剔除對應的節點
            pre.next = cur.next;
            cur = cur.next;
        }
        return pre.val;
    }
    //建立連結串列的節點類
    public class LinkNode{
        int val;
        LinkNode next = null;
        LinkNode(int val){
            this.val = val;
        }
    }
}