当前位置: 首页 > news >正文

阿里 约瑟夫环问题

题目要求:实现一个约瑟夫环(Josephus problem):N个人围成一圈,从第一个人开始按顺序报数,每数到第M个人就把他淘汰(出局),然后从下一个人重新报数。如此重复,直到只剩最后一个人。请问最后剩下的人最初在什么位置(或编号)

举例:

例1:N=5,M=2
圆圈:1,2,3,4,5

  • 从1数,2出局,剩下:1,3,4,5(从3开始)

  • 数到4出局,剩下:1,3,5(从5开始)

  • 数到1出局,剩下:3,5(从3开始)

  • 数到5出局,剩下:3 ✅(幸存者是3号)

例2:N=7,M=3 → 最后幸存者是4号。

一、模拟法:

1.思路:模拟约瑟夫环逐个淘汰的过程

(1)初始时有n个人,全部未出局。

(2)循环直到只剩一人

(a)移动到下一个人(如果循环到第n个后需要回到第1个)

(b)如果这个人未出局,报数+1

(c)如果报数达到m:标记此人出局,打印出局信息,重置报数计数器为0,将剩余人数 - 1

(3)遍历查找唯一的未出局者,返回其编号

2.复杂度分析:

(1)时间复杂度:O(n × m),需要淘汰n - 1个人,每淘汰一个人都要检查m个元素,当n较大时效率低。当m接近于n时,时间复杂度最坏可达到O(n^2)。

(2)空间复杂度:O(n)。额外需要一个boolean数组存储当前位是否已经淘汰。

附代码:

class Solution { public int josephus(int n, int m) { // 使用数组标记是否出局 boolean[] out = new boolean[n + 1]; // 1-indexed,下标0不用 int count = n; // 剩余人数 int i = 0; // 当前位置 int step = 0; // 已报数步数 while (count > 1) { i++; if (i > n) i = 1; if (!out[i]) { step++; if (step == m) { out[i] = true; System.out.printf("出局: %d\n", i); step = 0; count--; } } } // 找出幸存者 for (i = 1; i <= n; i++) { if (!out[i]) return i; } return -1; } }

ACM模式:

import java.util.Scanner; class Solution { public int josephus(int n, int m) { // 使用数组标记是否出局 boolean[] out = new boolean[n + 1]; // 1-indexed,下标0不用 int count = n; // 剩余人数 int i = 0; // 当前位置 int step = 0; // 已报数步数 while (count > 1) { i++; if (i > n) i = 1; if (!out[i]) { step++; if (step == m) { out[i] = true; System.out.printf("出局: %d\n", i); step = 0; count--; } } } // 找出幸存者 for (i = 1; i <= n; i++) { if (!out[i]) return i; } return -1; } } public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int n = scanner.nextInt(); int m = scanner.nextInt(); Solution solution = new Solution(); int survivor = solution.josephus(n, m); System.out.println("幸存者: " + survivor); scanner.close(); } }

二、递推公式法(最优解):

1.思路:不模拟淘汰过程,而是反向推导:已知1个人时的幸存者位置,推出第2个人、3个人......直到n个人时的幸存者位置。

2.递推公式:

f(1) = 0 // 只有1个人时,幸存者索引是0(0-indexed)
f(n) = (f(n-1) + m) % n // 增加第n个人后,新幸存者索引的计算公式

对应代码实现:

for (int i = 2; i <= n; i++) { // 从2个人开始递推,直到n个人 survivor = (survivor + m) % i; // 核心递推公式 }

3.公式解释:

(1)假设已知n - 1个人的时候,幸存者索引为f(n - 1),它是在旧圈中的位置

(2)当人数从n - 1增加到n时,相当于在圆圈中插入了一个新的人(编号0)

(3)报数时会跳过m个人,所以新幸存者的索引要在旧索引的基础上向后移动m步

(4)再对当前人数n取模(因为是圆圈结构)

4.复杂度分析:

(1)时间复杂度:O(n),只需要1次循环。

(2)空间复杂度:O(1),只需要一个变量survivor。

附代码:

class Solution { public int josephus(int n, int m) { if (n <= 0 || m <= 0) return -1; // 参数合法性检查 int survivor = 0; // 初始:f(1) = 0(n = 1时,幸存者在第0个位置) for (int i = 2; i <= n; i++) { // 从2个人开始递推,直到n个人 survivor = (survivor + m) % i; // 核心递推公式 } // 这个代码只能拿到最终的幸存者编号,无法拿到每轮出局的人是谁 return survivor + 1; // 题目通常要求1-indexed(编号从1开始) } }

ACM模式:

import java.util.Scanner; class Solution { public int josephus(int n, int m) { if (n <= 0 || m <= 0) return -1; // 参数合法性检查 int survivor = 0; // 初始:f(1) = 0(n = 1时,幸存者在第0个位置) for (int i = 2; i <= n; i++) { // 从2个人开始递推,直到n个人 survivor = (survivor + m) % i; // 核心递推公式 } // 这个代码只能拿到最终的幸存者编号,无法拿到每轮出局的人是谁 return survivor + 1; // 题目通常要求1-indexed(编号从1开始) } } public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int n = scanner.nextInt(); int m = scanner.nextInt(); Solution solution = new Solution(); int survivor = solution.josephus(n, m); System.out.println("幸存者: " + survivor); scanner.close(); } }
http://www.jsqmd.com/news/760811/

相关文章:

  • ARM NEON技术:SIMD加速与优化实践
  • VLA-4D:多模态感知与动态适应的机器人视觉系统
  • Python量化交易实战指南:jqktrader同花顺自动化交易工具深度解析
  • 快速生成mobaxterm中文设置向导,告别繁琐的手动配置
  • M5Stamp C3开发板:RISC-V架构物联网开发实战
  • 今天拆 8 个国外项目/需求信号:普通人怎么把“开源工具、README、AI 原型、数字模板”变成小生意?
  • 以太网网口差分信号、隔离变压器、电压/电流型PHY 深度总结
  • 利用快马平台快速构建jrebel离线激活演示原型,十分钟搞定热部署环境
  • Coze多Agent协作系统实战:从入门到生产级应用
  • AI编码代理执行力插件:反偷懒机制与多Agent协作优化
  • 【PHP AI校验黄金标准】:基于ISO/IEC 30107-1的活体检测+OCR双模校验框架(含FAR<0.001%实测数据)
  • R 4.5并行计算效率为何卡在1.2x?——揭秘RcppParallel与future::plan的底层调度冲突
  • 基于Ansible与Tmux构建云端AI开发环境:实现24/7远程编程
  • 解锁纯净动漫世界:Hanime1Plugin如何让你的Android观影体验焕然一新
  • 拆解UL 9540A:你的家用储能系统安全吗?从标准看热失控防火设计关键点
  • HTML 数独小游戏
  • 实战演练:基于快马平台生成具备完整交互的微信小程序社区论坛模块
  • 【Dify医疗合规调试实战指南】:20年资深架构师亲授3大避坑法则与5步合规上线流程
  • R 4.5空间可视化革命:如何用全新geom_sf_interactive()实现百万级点动态聚类+点击穿透分析?
  • R 4.5回测黄金组合配置:xts 0.13.1 + PerformanceAnalytics 2.0.15 + blotter 0.15.5 —— 经沪深300十年滚动回测验证的稳定性铁三角
  • 2026年锂电池应用白皮书户外储能供电方案解析:太阳能控制器、储能电源、储能电池、磷酸铁锂电池、光伏控制器、逆变器选择指南 - 优质品牌商家
  • UniPercept框架:大语言模型的多模态视觉理解突破
  • TrafficMonitor插件完全指南:让你的Windows任务栏变身全能信息中心
  • 互联网大厂 Java 求职面试:从基础到微服务的技术深潜
  • 第30篇:Vibe Coding时代:LangGraph 评估体系实战,解决 Agent 效果只能凭感觉判断的问题
  • CGRA编译器级功耗建模技术解析与应用
  • 实战应用:开发一款用户可自助解决vcruntime140.dll错误的桌面工具
  • 正实数集合 连同这些运算是否构成向量空间?
  • 避坑指南:在Ubuntu 20.04上从零搭建OpenPCDet+ROS的PointPillars可视化环境
  • 新手友好:跟快马AI学做第一个基图1096式图片展示网页