用静态数组模拟单向循环链表解约瑟夫环,核心是next[i]存下一个存活者下标,通过下标跳转实现循环链接,内存紧凑、无GC压力;初始化next[i]=(i+1)%n成环,淘汰时通过prev定位target并重连next[prev]=next[target],m=1时特判优化。
在 java 中用静态数组模拟单向循环链表来解约瑟夫环问题,核心是**不依赖动态节点对象,而是用整型数组存“下一个位置索引”**,通过下标跳转实现逻辑上的循环链接。这种方式内存紧凑、无 gc 压力,适合大规模人数场景(如 n=10⁶)。
一、静态数组如何模拟单向循环链表
不用 Node 类,改用两个平行数组:
-
next[]:长度为
n的 int 数组,next[i]表示编号为i的人「顺时针」下一个还存活的人的下标; -
alive[](可选):boolean 数组标记是否存活;但更省空间的做法是——只用
next数组,并约定next[i] == -1表示已淘汰。
初始化时让每个人指向下一个:
next[i] = (i + 1) % n(最后一人指回第 0 人),形成闭环。
二、约瑟夫环的模拟逻辑(报数 m,从 0 开始)
关键不是“删除”,而是“跳过”和“重连”。设当前报数起点为 cur,要淘汰第 m 个人(即从 cur 数起第 m-1 个存活者):
- 先走
m-2步,到达待淘汰者的前一个人prev; - 令
target = next[prev],即待淘汰者; - 执行“删除”:
next[prev] = next[target]; - 下一轮起点就是
next[prev](即淘汰者后一人)。
⚠️ 注意:当 m == 1 时,每轮都淘汰当前人,可直接设 next[cur] = next[next[cur]] 并移动 cur,避免单独循环。
三、完整可运行代码(含注释)
// 输入:n 人数,m 报数周期(从第 1 人开始报 1)
public static int josephusArray(int n, int m) {
if (n == 1) return 0;
int[] next = new int[n];
// 初始化环:0→1→2→...→n-1→0
for (int i = 0; i int cur = 0; // 当前报数起点(从 0 号开始报 1)
// 剩余人数 > 1 才继续
while (n > 1) {
// 找到待淘汰者的前驱:从 cur 出发,走 m-2 步(因为 cur 自己算第 1 个)
int prev = cur;
for (int i = 1; i <p>}</p>
四、优化与注意事项
- 时间复杂度:朴素版 O(n×m),当 m 很大时可用「模运算跳步」优化至 O(n),但需额外处理环长变化,初学建议先掌握基础逻辑;
-
边界处理:m 可能大于当前剩余人数,应取
m % currentSize(若为 0 则等价于currentSize); -
返回值意义:函数返回的是**原始编号(0-based)**,如需 1-based 结果,返回
result + 1; - 对比链表实现:数组版无对象创建开销,缓存友好;但无法动态增删,且调试时下标易错——建议手画 5 人环走两轮验证。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











