【DP】LeetCode 剑指 Offer 62. 圆圈中最后剩下的数字
题目链接
思路
经典约瑟夫环问题,可以使用找规律的方法进行解决。
以 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!(重点!)
下图展示了通过 F(7,3)
反推 F(8,3)
的过程。
通过图中过程可以看到,如果我们知道了 F(7,3)
的值,那么可以反推出 F(8,3)
的值。而如果要知道 F(7,3)
的值,我们只需要知道 F(6,3)
的值。
以此类推,有一项值是我们已经知道的,即 F(1,3) = 0
。
所以可以写出递推公式
\[f(n, m)= \begin{cases}0 & n=1 \\ {[f(n-1, m)+m] \% n} & n>1\end{cases}
\]
因为 m
是给定且不变的,我们就简写成 f(n)
并且 f(n)
只与 f(n-1)
有关,所以可以把 f(n-1)
记录为一个单变量 pre
,通过不断更新 pre
来达到计算最终结果的目的。
代码
class Solution {
public int lastRemaining(int n, int m) {
int pre = 0;
for(int i = 2; i <= n; i++){
pre = (pre + m) % i;
}
return pre;
}
}