出自leetcode上的題庫 —— 圓圈中最後剩下的數字,乍看這道題用迴圈鍊錶解決,奈何輸入的數值太大,程式不是超出記憶體限制就是超出時間限制,力扣上已經有大大通過數學公式解決了這道題,不過很不服氣的我還是嘗試了好幾次迴圈鍊錶(沒成功_(:d)∠)_)
0,1,,n-1這n個數字排成乙個圓圈,從數字0開始,每次從這個圓圈裡刪除第m個數字。求出這個圓圈裡剩下的最後乙個數字。例如,0、1、2、3、4這5個數字組成乙個圓圈,從數字0開始每次刪除第3個數字,則刪除的前4個數字是2、0、4、1,因此最後剩下的數字是3。
示例 1:
輸入: n = 5, m = 3
輸出: 3
示例 2:
輸入: n = 10, m = 17
輸出: 2
限制:1 <= n <= 10^5
1 <= m <= 10^6
甜姨(@sweetiee)在題解中提了一下下,linkedlist刪除乙個節點的時間複雜度為o(1),但是要找到對應的節點需要乙個個遍歷,時間複雜度為o(n),而使用arraylist勉強可以不超時,雖然arraylist查詢乙個節點的時間複雜度為o(1),刪除乙個節點的時間複雜度為o(n),但是因為刪除節點時,後繼節點的前移是連續記憶體空間的拷貝,效率會比linkedlist快
不過我想,我們可以提高鍊錶的查詢效率呀!通過雙向迴圈鍊錶,一定程度上可以減少要查詢的節點個數
我們可以用乙個整型記錄當前結點的數量,這個值還可以作為跳出while迴圈的條件。當移動的步長大於當前節點的數量時,可以對移動次數進行縮減,去掉冗餘的"轉圈圈"次數,經過測試還是不夠快,測試數值在50000+節點數量時就報了超時錯誤。所以節點不能只是單純的向前移動,如果要刪除的點更偏向於當前節點的前部,那麼應當向前移動,這也是設計成雙向的原因。
即便如此仍然沒能打敗70000+的測試數值,雙向迴圈鍊錶在執行70000+節點數量時,大概需要2 ~ 4秒的時間(欲哭無淚)
// 內部類
private class
node
}public int
lastremaining(int
n, int
m) //
構造雙向迴圈鍊錶
node root = new
node(0);
node tail = root, prenode;
for
(int
i = 1; i < n; i++)
tail.nextnode = root;
root.prenode = tail;
node currnode = root;
int
nodenum = n;
while
(nodenum != 1) else if
(m % nodenum == 0) else
// 決定向前還是向後移動
if (movetimes > nodenum / 2)
} else
}//
刪除節點
node tmp = currnode.prenode;
tmp.nextnode = currnode.nextnode;
currnode = currnode.nextnode;
currnode.prenode = tmp;
nodenum--;
}return
currnode.nodevalue;
}測試用例:
71989, 111059
輸出:
34203(耗時2 ~ 4秒)
圓圈中最後剩下的數字
1.問題描述 題目0,1.n 1這n個數字排成乙個圓圈,從數字0開始每次從這個圓圈裡刪除第m個數字。求出這個圓圈裡剩下的最後乙個數字。來自 劍指offer 2.分析 1 用環形鍊錶模擬圓圈,然後掃瞄鍊錶刪除結點,如果掃瞄到了鍊錶結尾,重新在指向鍊錶開頭以此來模擬環形鍊錶。typedef struct...
圓圈中最後剩下的數字
題目描述 每年六一兒童節,牛客都會準備一些小禮物去看望孤兒院的小朋友,今年亦是如此。hf作為牛客的資深元老,自然也準備了一些小遊戲。其中,有個遊戲是這樣的 首先,讓小朋友們圍成乙個大圈。然後,他隨機指定乙個數m,讓編號為0的小朋友開始報數。每次喊到m 1的那個小朋友要出列唱首歌,然後可以在禮品箱中任...
圓圈中最後剩下的數字
題目 0,1,n 1這n個數字排成乙個圓圈,從數字0開始每次從這個圓圈裡刪除第m個數字。求這個圓圈裡剩下的最後乙個數字。分析 1.利用環形鍊錶模擬圓圈求解。2.利用刪除之後的規律求解。環形鍊錶 class solution circleiter circlelist.begin while circ...