约瑟夫问题
这个问题实际上是约瑟夫问题,这个问题描述是
N个人围成一圈,第一个人从1开始报数,报M的将被杀掉,下一个人接着从1开始报。如此反复,最后剩下一个,求最后的胜利者。
从8个人开始,每次杀掉一个人,去掉被杀的人,然后把杀掉那个人之后的第一个人作为开头重新编号
第一次C被杀掉,人数变成7,D作为开头,(最终活下来的G的编号从6变成3)
第二次F被杀掉,人数变成6,G作为开头,(最终活下来的G的编号从3变成0)
第三次A被杀掉,人数变成5,B作为开头,(最终活下来的G的编号从0变成3)
以此类推,当只剩一个人时,他的编号必定为0!(重点!)
从最终活着的人编号的反推
f(n) 可由 f(n - 1)得到,f(n - 1)可由 f(n - 2)得到,……,f(2)可由 f(1)得到;因此,若给定 f(1) 的值,就可以递推至任意 f(n)。而F(1,m)的解 f(1) = 0 恒成立,即无论 m为何值,长度为 1 的数字环留下的是一定是数字 0。
动态规划解析:
状态定义: 设(i,m)的解为 dp[i] ;
转移方程: 通过以下公式可从 dp[i - 1]递推得到 dp[i] ;
dp[i] = (dp[i - 1] + m) %( i+1)
初始状态:(1,m)的解恒为 00,即 dp[1] = 0 ;
返回值: 返回(n,m)的解 dp[n];
class Solution:
def lastRemaining(self, n,m):
if n==1: return 0
dp=[0]*n
for i in range(1,n):
dp[i]=(dp[i-1]+m)%(i+1)
return dp[n-1]
根据状态转移方程的递推特性,无需建立状态列表 dpdp ,而使用一个变量 xx 执行状态转移即可。
class Solution:
def lastRemaining(self, n,m):
if n==1: return 0
x=0
for i in range(1,n):
x=(x+m)%(i+1)
return x