【DP】LeetCode 剑指 Offer 62. 圆圈中最后剩下的数字

发布时间 2023-03-22 21:09:23作者: Frodo1124

题目链接

剑指 Offer 62. 圆圈中最后剩下的数字

思路

经典约瑟夫环问题,可以使用找规律的方法进行解决。

n = 8, m = 3为例,下面这幅图展示了模拟执行的全过程,用 F(n,m) 表示最后存活的人的索引。

image

从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) 的过程。

image

通过图中过程可以看到,如果我们知道了 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;
    }
}