3種方法: 圓圈中最後剩下的數字


題目

NO. 1579

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


解法一(暴力法)

思路:使用數組申請一塊內存(也可以使用鏈表),按照要求循環執行n-1次移除操作,最後剩下的元素即爲所求

  1. 申請一塊連續內存,存放0到n的數值
  2. 位置索引按照題目要求計算,數組中索引從0開始,需要根據移動個數減一
  3. 最後一個數值即爲所求
  • 時間複雜度:O(n)
  • 空間複雜度:O(n)
# author: [email protected]
class Solution:
    def lastRemaining(self, n: int, m: int) -> int:
        cnt, rmIdx = n, m
        circle = [k for k in range(0,cnt)]
        for i in range(1,n):
            rmIdx = rmIdx%cnt - 1 #索引從0開始,計數從1開始
            tmpVal = circle.pop(rmIdx)
            cnt -= 1
            rmIdx = rmIdx + m if rmIdx >= 0 else m #索引爲-1時,直接賦值m
        return circle.pop()

解法二(遞歸)

思路:約瑟夫環的公式爲:f(n,m)=[f(n1,m)+m]%nf(n,m) = [f(n-1,m)+m]\%n,具體原理,我也沒搞懂。
思路:約瑟夫環的遞推公式爲:f(n,m) = [f(n-1,m) + m] % n,具體原理,我也沒搞懂,如果有明白的朋友,希望不吝賜教。

大概意思是,n-1個數值的最後剩餘數值向右移動m位,即得到,n個數時最後剩餘的數值(對n求餘是,在超出數值時繼續重0開始編號,爲了形成環,這個我知道),具體原因,我也沒理解。

看了一些解釋,過程是,每次刪除一個數後,從被刪位置的下一個位置,從零開始重新循環編號。

  1. 當只有一個數據時,返回唯一的可能情況:0
  2. 遞歸得到上一次刪除最後剩餘的值 x
  3. 上一次的結果加入後,從x作爲計數開始
  • 時間複雜度:O(n)
  • 空間複雜度:O(1)
# author: [email protected]
class Solution:
    def lastRemaining(self, n: int, m: int) -> int:
        if n == 1:
            return 0
        x = self.lastRemaining(n-1,m)
        return (m + x) % n

解法三(循環)

思路:將遞歸的思路,使用循環實現

  • 時間複雜度:O(n)
  • 空間複雜度:O(1),另外也減少了棧空間的申請
# author: [email protected]
class Solution:
    def lastRemaining(self, n: int, m: int) -> int:
        last = 0
        for i in range(1,n):
            last = (last + m) % (i + 1)
        return last

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章