AlgoMooc
图解算法/数据结构/约瑟夫问题

约瑟夫问题

28 / 28基础内容

数据结构动画

约瑟夫问题

加载中
正在加载动画引擎...

本课导读

约瑟夫问题:n 个人围成一圈,从某人开始报数,每数到第 k 个人就出局,问最后谁能幸存。围圈 + 不断删除,正是循环链表的招牌应用。

你将学到
  • 循环链表模拟:删一个节点后继续往下转
  • 数学递推 f(n) = (f(n-1)+k) % n,O(n) 直接算
  • 识别「围圈淘汰」一类问题

约瑟夫问题是什么

约瑟夫问题(Josephus Problem)是一个古老的数学游戏。传说犹太历史学家约瑟夫和40个士兵被罗马军队包围,他们决定围成一圈,从某个人开始依次报数,每报到第k个人就处决他,然后从下一个人重新报数,直到剩下最后一个人。约瑟夫希望自己成为最后幸存者,于是研究了如何站位。简单说,就是n个人围成一圈,每数到m就淘汰一人,求最后幸存者的初始位置

为什么适合用循环链表模拟

游戏过程天然是一个环形结构:每个人是一个节点,报数相当于遍历链表,淘汰就是删除节点。循环链表恰好能模拟这种“转圈”行为,无需处理数组越界或取模运算。而且删除操作只需修改指针,效率高。类比:就像一群小朋友手拉手围成一圈,每次喊到数字的人就松手离开,剩下的人自动拉手继续。

模拟过程与时间复杂度

用循环链表模拟:从起点开始,每走m-1步删除一个节点,重复直到只剩一个节点。每次删除需要O(m)步,总共删除n-1次,所以时间复杂度为O(n·m)。当n和m很大时,效率较低。但优点是直观,适合理解问题。就像手动模拟游戏,一步步淘汰,虽然慢但清晰。

数学递推公式 O(n) 解法

其实约瑟夫问题有更高效的数学解法。定义f(n)为n个人、报数到m时幸存者的编号(从0开始)。递推公式:f(1)=0f(n)=(f(n-1)+m) % n。这个公式基于:第一轮淘汰第m-1号后,剩下n-1个人重新编号,幸存者在旧编号中的位置可以通过逆推得到。只需O(n)时间,无需模拟。就像找到规律后直接计算,不用一步步淘汰。

在面试和现实中的意义

约瑟夫问题是面试中经典的链表与数学综合题。它考察对环形数据结构的理解、模拟能力以及数学建模思维。现实意义:可用于任务调度(如循环分配资源)、网络令牌环协议、甚至某些加密算法。学会它,你不仅掌握了一个具体算法,更锻炼了从问题抽象出模型的能力。

吴师兄提示:看到「围成圈不断淘汰」就想循环链表。

学完练一练

把刚学的结构放进 LeetCode 题里用一次。

去图解题库实战