打敗演算法 圓圈中最後剩下的數字

2022-05-09 02:27:11 字數 1868 閱讀 6500

出自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...