孩子們的遊戲(圓圈中最後剩下的數)
每年六一兒童節,牛客都會準備一些小禮物去看望孤兒院的小朋友,今年亦是如此。HF作爲牛客的資深元老,自然也準備了一些小遊戲。其中,有個遊戲是這樣的:首先,讓小朋友們圍成一個大圈。然後,他隨機指定一個數m,讓編號爲0的小朋友開始報數。每次喊到m-1的那個小朋友要出列唱首歌,然後可以在禮品箱中任意的挑選禮物,並且不再回到圈中,從他的下一個小朋友開始
,繼續0…m-1報數…這樣下去…直到剩下最後一個小朋友,可以不用表演,並且拿到牛客名貴的“名偵探柯南”典藏版(名額有限哦!!_)。請你試着想下,哪個小朋友會得到這份禮品呢?(注:小朋友的編號是從0到n-1)
package client;
public class Solution {
public int LastRemaining_Solution(int n, int m) {
// 如果有n個小朋友,那麼return -1
if(n==0)return -1;
// 想想成爲 把小朋友手拉手,即爲一個環形鏈表
Node root = getNodeLink(n);
// root的前驅節點
Node r = null ;
/*當環的下一個節點不是自己的時候,即就是環裏面只剩自己,
那麼這個節點即爲所要求的節點,
退出while循環,*/
while(root.next!=root){
/*這裏爲什麼是m-2,不是m-1;因爲 這是單向循環鏈表,
我們要想當前節點消失,那麼循環停止時需要停到當前節點的前一個節點
,顧循環應該少循環一次*/
for(int i =0;i<=m-2;i++){
// r始終爲root的前驅節點
r = root;
root = root.next;
}
/* 需要刪除的節點的前一個節點的next指針指向 當前節點的下一個節點,
即就是刪除了該節點*/
r.next = root.next;
/* 當前節點需要指向自己的下一級節點,因爲 刪除了 當前節點,下一次
開始數數的就是當前節點的下一個節點,即就是題中高亮部分從下一個小朋友開始 */
root = root.next;
}
//返回最後的數據
return root.num;
}
public static Node getNodeLink(int n){
Node root = new Node();
Node curr = root;
curr.num = 0;
for(int i=1;i<n;i++){
Node node = new Node();
node.num = i;
curr.next = node;
curr = node;
}
curr.next = root;
return root;
}
public static void main(String[] args) {
int lastRemaining_Solution = new Solution().LastRemaining_Solution(6, 6);
System.out.println(lastRemaining_Solution);
}
}
class Node{
public Node next;
public int num;
}
運行結果:
思索過程:
- 讀到這個題的時候,我就想到這個一個約瑟夫環問題,數據結構沒有白學~~,然後就想着把這個問題轉化成小朋友手拉手的問題,也就是 形成一個 單向循環鏈表,緊接着就是數數,數數可以想象成一個for循環,一次固定 循環
m-1
次,即就是循環0~m-1
次(注意:代碼部分寫的是m-2,已經解釋過了,此處不再囉嗦),在循環內,指針不斷移動,for循環出來,指針移除當前節點,進行轉換操作。代碼整個部分,我們不用關心哪個小朋友數哪個數
,把小朋友數數就想像成在每一輪的循環裏 執行指針後移操作
,這道題便迎刃而解了。