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=8 m=3的例子
我們定義f(n,m)表示最後剩下那個人的索引號,因此我們只關係最後剩下來這個人的索引號的變化情況即可
從8個人開始,每次殺掉乙個人,去掉被殺的人,然後把殺掉那個人之後的第乙個人作為開頭重新編號
第一次c被殺掉,人數變成7,d作為開頭,(最終活下來的g的編號從6變成3)
第二次f被殺掉,人數變成6,g作為開頭,(最終活下來的g的編號從3變成0)
第三次a被殺掉,人數變成5,b作為開頭,(最終活下來的g的編號從0變成3)
以此類推,當只剩乙個人時,他的編號必定為0!(重點!)
3 最終活著的人編號的反推
現在我們知道了g的索引號的變化過程,那麼我們反推一下
從n = 7 到n = 8 的過程
如何才能將n = 7 的排列變回到n = 8 呢?
我們先把被殺掉的c補充回來,然後右移m個人,發現溢位了,再把溢位的補充在最前面
神奇了 經過這個操作就恢復了n = 8 的排列了!
因此我們可以推出遞推公式f(8,3)=[f(7,3)+3]%8
進行推廣泛化,即f(n,m)=[f(n−1,m)+m]%n
4 遞推公式的匯出
再把n=1這個最初的情況加上,就得到遞推公式
f(n,m)=0,n=1
f(n,m)=[f(n−1,m)+m]%n,n>1
class solution(object):
def lastremaining(self, n, m):
""":type n: int
:type m: int
:rtype: int
"""p = 0
for i in range(2, n + 1):
p = (p + m) % i
return p
面試題62 圓圈中最後剩下的數字
面試題62 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...
面試題62 圓圈中最後剩下的數字
1.題目描述 0,1,n 1這n個數字排成乙個圓圈,從數字0開始,每次從這個圓圈裡刪除第m個數字。求出這個圓圈裡剩下的最後乙個數字。例如,0 1 2 3 4這5個數字組成乙個圓圈,從數字0開始每次刪除第3個數字,則刪除的前4個數字依次是2 0 4 1,因此最後剩下的數字是3。示例 示例 1 輸入 n...
面試題62 圓圈中最後剩下的數字
題目 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 ...