约瑟夫环问题

简介

这个问题是以弗拉维奥·约瑟夫命名的,他是1世纪的一名犹太历史学家。他在自己的日记中写道,他和他的40个战友被罗马军队包围在洞中。他们讨论是自杀还是被俘,最终决定自杀,并以抽签的方式决定谁杀掉谁。约瑟夫斯和另外一个人是最后两个留下的人。约瑟夫斯说服了那个人,他们将向罗马军队投降,不再自杀。约瑟夫斯把他的存活归因于运气或天意,他不知道是哪一个。 —— 【约瑟夫问题】维基百科

例子

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

0,1,···,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字(删除后从下一个数字开始计数)。求出这个圆圈里剩下的最后一个数字。

例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。

思路:

  • 最初 0 1 2 3 4 5,m 为 3
  • 第一轮后 3 4 5 0 1
  • 可以得出,每一轮其实就是把数字往前以 m 位
  • 当只剩一个数时它在第 0 位,这个点是不被删除的,所以可以通过倒推,找到其原始位置
  • 第一轮时,将其往后移 m 位,同时模上这一轮的数量
  • 第二轮同理
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class Solution {
    public int lastRemaining(int n, int m) {
        // res 为最终的位置
        int res = 0;
        for (int i = 1; i < n; i++) {
            // 倒数第 i 轮
            res = (res + m) % (i + 1);
        }
        return res;
    }
}
updatedupdated2022-06-232022-06-23