doocs/leetcode 题解精讲:面试题 62「圆圈中最后剩下的数字」的约瑟夫环递推与多语言实现
示例工程【免费下载链接】leetcodeLeetCode solutions in any programming language | 多种编程语言实现 LeetCode、《剑指 Offer第 2 版》、《程序员面试金典第 6 版》题解项目地址https://gitcode.com/doocs/leetcode点击查看免费下载本篇技术指南以 doocs/leetcode 仓库中 面试题 62. 圆圈中最后剩下的数字 的官方题解为骨架完整讲解约瑟夫环Josephus Problem问题的数学推导、递归解法与迭代优化并给出仓库内 Python、Java、C、Go、JavaScript、C#、Swift 的对照实现。读完本文你将掌握 $f(n,m)(mf(n-1,m))\bmod n$ 这一核心递推式的推导过程、时间复杂度与空间复杂度分析并能将同一思路迁移到 1823. 找出游戏的获胜者 等同类环形淘汰问题。题目概述0,1,···,n-1 这 n 个数字排成一个圆圈从数字 0 开始每次从这个圆圈里删除第 m 个数字删除后从下一个数字开始计数。求出这个圆圈里剩下的最后一个数字。例如0、1、2、3、4 这 5 个数字组成一个圆圈从数字 0 开始每次删除第 3 个数字则删除的前 4 个数字依次是 2、0、4、1因此最后剩下的数字是 3。删除过程如下第 1 轮从 0 开始数第 3 个数字是 2删除 2从 3 继续计数第 2 轮从 3 开始数第 3 个数字是 0删除 0从 1 继续计数第 3 轮从 1 开始数第 3 个数字是 4删除 4从 1 继续计数第 4 轮从 1 开始数第 3 个数字是 1删除 1剩下 3。示例 1输入: n 5, m 3 输出: 3示例 2输入: n 10, m 17 输出: 2限制1 n 10^51 m 10^6从数据范围可以看出n 最大可达 $10^5$若采用链表或数组模拟每轮删除一个数字虽然直观但每次定位第 m 个数字需要 $O(n)$ 的遍历整体复杂度达到 $O(n^2)$在 n 较大时无法通过而 m 可远大于 n如示例 2 中 m17、n10此时取模运算在推导中扮演关键角色。这正是需要数学递推解法的原因。核心递推从删除一个数字后的编号重映射说起设 $f(n, m)$ 表示从 n 个数中每次删除第 m 个最后剩下的是第几个数字编号从 0 开始。第一次我们删除了第 m 个数字编号为 $(m-1) \bmod n$剩下的 n-1 个数重新组成一个圆圈并且下一次计数从被删除数字的下一个数字开始。此时这 n-1 个数的相对编号被重新组织为 $0, 1, \cdots, n-2$。设 $x f(n - 1, m)$它表示从重新编号后的 n-1 个数中每次删除第 m 个最后剩下的是这 n-1 个数中的第几个相对编号。那么 $f(n, m)$ 应该如何从 x 还原关键在于建立相对编号与原始编号之间的映射关系原始编号为 $(m \bmod n)$ 的数字在删除第 m 个数字后成为新一轮计数起点其相对编号为 0因此原始编号 $ (m \bmod n \text{相对编号}) \bmod n$。于是有核心递推式$$ f(n, m) (m \bmod n x) \bmod n (m f(n-1, m)) \bmod n $$边界条件为$$ f(1, m) 0 $$当 n 为 1 时圆圈中只剩数字 0最后留下的数字序号一定为 0。为什么可以写成 $(m x) \bmod n$由于 $x f(n-1, m) \in [0, n-2]$而 $(m \bmod n x)$ 可能超过 n因此需要再次对 n 取模。而 $(m \bmod n x) \bmod n$ 与 $(m x) \bmod n$ 在数学上是等价的模运算的结合律所以仓库题解中直接写成 $(m x) \bmod n$ 即可无需先对 m 取模。小规模验证以 n 5、m 3 为例逐步递推$f(1, 3) 0$$f(2, 3) (3 0) \bmod 2 1$$f(3, 3) (3 1) \bmod 3 1$$f(4, 3) (3 1) \bmod 4 0$$f(5, 3) (3 0) \bmod 5 3$最终得到 $f(5, 3) 3$与题目示例输出一致验证了递推式的正确性。方法一数学 递归根据上述递推式可以直接写出递归解法。递归求解即可也可以改成迭代。各语言实现Python3见 Solution.pyclass Solution: def lastRemaining(self, n: int, m: int) - int: def f(n, m): if n 1: return 0 x f(n - 1, m) return (m x) % n return f(n, m)Java见 Solution.javaclass Solution { public int lastRemaining(int n, int m) { return f(n, m); } private int f(int n, int m) { if (n 1) { return 0; } int x f(n - 1, m); return (m x) % n; } }C见 Solution.cppclass Solution { public: int lastRemaining(int n, int m) { return f(n, m); } int f(int n, int m) { if (n 1) { return 0; } int x f(n - 1, m); return (m x) % n; } };Go见 Solution.gofunc lastRemaining(n int, m int) int { var f func(n, m int) int f func(n, m int) int { if n 1 { return 0 } x : f(n-1, m) return (m x) % n } return f(n, m) }Swift见 Solution.swiftclass Solution { func lastRemaining(_ n: Int, _ m: Int) - Int { return f(n, m) } private func f(_ n: Int, _ m: Int) - Int { if n 1 { return 0 } let x f(n - 1, m) return (m x) % n } }复杂度分析时间复杂度$O(n)$每次递归只做一次取模运算共递归 n 层空间复杂度$O(n)$递归调用栈深度为 n。当 n 达到 $10^5$ 时部分语言的默认栈深度可能告警因此实际工程中更推荐方法二的迭代写法见下文。方法二数学 迭代自底向上递归深度为 n。同一递推式可以自底向上从 2 滚到 n只需要一个变量空间降为常数 $O(1)$彻底规避递归栈溢出风险。递推的迭代展开令 f 从 0 开始对应 $f(1, m)0$随后对 i 从 2 到 n 依次执行 $f (f m) \bmod i$。各语言实现Python3见 Solution2.pyclass Solution: def lastRemaining(self, n: int, m: int) - int: f 0 for i in range(2, n 1): f (f m) % i return fJava见 Solution2.javaclass Solution { public int lastRemaining(int n, int m) { int f 0; for (int i 2; i n; i) { f (f m) % i; } return f; } }C见 Solution2.cppclass Solution { public: int lastRemaining(int n, int m) { int f 0; for (int i 2; i n; i) { f (f m) % i; } return f; } };Go见 Solution2.gofunc lastRemaining(n int, m int) int { f : 0 for i : 2; i n; i { f (f m) % i } return f }JavaScript见 Solution.js 中的迭代版本/** * param {number} n * param {number} m * return {number} */ var lastRemaining function (n, m) { let f 0; for (let i 2; i n; i) { f (f m) % i; } return f; };C#见 Solution.cspublic class Solution { public int LastRemaining(int n, int m) { int f 0; for (int i 2; i n 1; i) { f (f m) % i; } return f; } }复杂度分析时间复杂度$O(n)$空间复杂度$O(1)$仅使用一个整型变量 f。这也是应对题目限制1 n 10^5的最优写法既不会像模拟法那样退化到 $O(n^2)$也不会像递归法那样产生 $O(n)$ 的调用栈。易错点与边界情况编号从 0 开始还是从 1 开始本题目编号为 0, 1, ···, n-1因此边界 $f(1, m)0$而 1823. 找出游戏的获胜者 中编号从 1 开始其递推式对应为 $ans (k f(n-1, k)) \bmod n$当结果为 0 时需要映射回 n见 Solution.py 等实现。两题递推本质相同差别仅在编号基线与取模结果的归一化处理。m 大于 n 的情况m 可达 $10^6$ 而 n 最大 $10^5$此时 m 可能远大于 n。递推式中 $(f m) \bmod i$ 的取模操作天然处理了这种情况无需额外对 m 取模预处理这也是递推解法的优势之一。递归爆栈方法一在最坏情况下递归深度等于 n$10^5$部分语言默认栈空间不足。若环境对递归深度有限制应优先使用方法二的迭代实现。int 溢出$(f m)$ 中 f 小于当前 i即小于 n最大 $10^5$m 最大 $10^6$两者之和不超过约 $1.1 \times 10^6$在 32 位 int 范围内完全安全各语言实现均无需使用长整型。同类问题扩展LeetCode 1823「找出游戏的获胜者」在 doocs/leetcode 仓库的 solution/1800-1899/1823.Find the Winner of the Circular Game/README.md 中收录了同一递推思路的变体n 名小伙伴围成一圈从编号 1 开始沿顺时针数 k 名小伙伴包含起始者最后被数到的人离开圈子求最终获胜者。该题与面试题 62 的差异在于编号从 1 而非 0 开始因此递推边界为 $f(1, k) 1$递推式为 $ans (k f(n-1, k)) \bmod n$当结果为 0 时代表编号 n需要显式归一化题目 n 仅到 500因此除了数学解法模拟法用数组 splice 删除在该数据范围内也能通过可以作为对照理解两种思路的适用边界。两题对比学习可以加深对编号重映射这一约瑟夫环核心思想的理解无论编号从几开始核心都是把 n 人问题的答案通过一轮删除后的相对编号递归或迭代地转化为 n-1 人问题的答案。小结面试题 62「圆圈中最后剩下的数字」是约瑟夫环问题的经典形式其最优解法建立在一条简洁的递推式之上$$ f(n, m) \begin{cases} 0, n 1 \ (m f(n-1, m)) \bmod n, n 1 \end{cases} $$方法一递归直接翻译递推式代码最直观时间复杂度 $O(n)$、空间复杂度 $O(n)$方法二迭代自底向上滚动计算时间复杂度 $O(n)$、空间复杂度 $O(1)$是应对 $n 10^5$ 数据范围的最优实现。在 doocs/leetcode 仓库中该题位于 lcof/面试题62. 圆圈中最后剩下的数字/ 目录包含 Python、Java、C、Go、JavaScript、C#、Swift 共 7 种语言的递归与迭代两套实现Solution 与 Solution2并可在 lcof/README.md 题解总表中检索到该题入口。掌握这条递推式及其推导过程后无论是面试手写还是应对环形淘汰类变体题如 1823都能快速给出线性时间、常数空间的优雅解法。赞分享示例工程【免费下载链接】leetcodeLeetCode solutions in any programming language | 多种编程语言实现 LeetCode、《剑指 Offer第 2 版》、《程序员面试金典第 6 版》题解项目地址https://gitcode.com/doocs/leetcode点击查看免费下载相关推荐CS-Notes 剑指 Offer 题解 62圆圈中最后剩下的数——约瑟夫环问题的递推公式与 O(1) 空间实现CS Notes 剑指 Offer 题解 62圆圈中最后剩下的数——约瑟夫环问题的递推公式与 O 1 空间实现 本篇基于 剑指 Offer 题解 62. 圆圈文档教程知识库剑指Offer No46「孩子们的游戏圆圈中最后剩下的数」约瑟夫环问题四种解法与递推公式详解剑指Offer No46「孩子们的游戏圆圈中最后剩下的数」约瑟夫环问题四种解法与递推公式详解 本文以 InterviewGuide 仓库中 46 剑指of文档教程知识库剑指 Offer 62 约瑟夫环最后剩下的数字从 O(nm) 模拟到 O(n) 动态规划LeetCode-Book剑指 Offer 62 约瑟夫环最后剩下的数字从 O nm 模拟到 O n 动态规划LeetCode Book 本篇围绕《剑指 Offer 62. 圆圈中示例工程教程教育上一篇VIC水文模型终极指南从配置陷阱到精准模拟的10个实战经验下一篇ReoGrid为企业级应用量身定制的.NET电子表格解决方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

CKEditor 4 Emoji 插件表情建议框的字体渲染测试解析:从 font.md 手册测试看彩色 Emoji 的实现与验证

CKEditor 4 Emoji 插件表情建议框的字体渲染测试解析:从 font.md 手册测试看彩色 Emoji 的实现与验证

前端UI组件 【免费下载链接】ckeditor4 The best enterprise-grade WYSIWYG editor. Fully customizable with countless features and plugins. 项目地址: https://gitcode.com/gh_mirrors/ck/ckeditor4 点击查看 免费下载 本篇技术指南以 CKEditor 4 仓库中的手册…

2026/10/16 2:33:54 阅读更多 →
lol-skins 仓库 Pulsefire Pantheon 炫彩皮肤包解析:80017–80024 清单、包结构与数据溯源

lol-skins 仓库 Pulsefire Pantheon 炫彩皮肤包解析:80017–80024 清单、包结构与数据溯源

【免费下载链接】lol-skins Comprehensive collection of League of Legends skins available for custom use. 项目地址: https://gitcode.com/gh_mirrors/lo/lol-skins 点击查看 免费下载 本篇技术指南以 lol-skins 仓库 中 Pulsefire Pantheon 炫彩包清单 为核心…

2026/10/16 2:33:54 阅读更多 →
OpenClaw Twitch 频道插件全解析:从版本演进到源码级配置实战

OpenClaw Twitch 频道插件全解析:从版本演进到源码级配置实战

人工智能大模型LLM 网关AI Agent即时通讯 【免费下载链接】openclaw-zero-token OpenClaw: Use All Major AI Models NO API Token! Claude/ChatGPT/Gemini/DeepSeek/Doubao/Grok/Qwen/Manus/Kimi 项目地址: https://gitcode.com/gh_mirrors/op/openclaw-zero-token…

2026/10/16 2:33:54 阅读更多 →

最新新闻

TPShop部署中的数据库验证:环境配置与排错完整指南

TPShop部署中的数据库验证:环境配置与排错完整指南

我敢说,十个声称"TPShop部署很简单"的人里,至少有七个会栽在数据库验证这一步。TPShop这套开源商城系统确实成熟,环境要求不高,安装文档也写得清楚,但正因为"看起来简单",大家往往在文…

2026/10/16 3:32:05 阅读更多 →
从单体到微服务:架构演进的实践与避坑指南

从单体到微服务:架构演进的实践与避坑指南

好端端一个单体应用,为什么要拆成微服务?这个问题我在各种技术讨论里听过无数次,自己也完整经历过一轮微服务架构演进历程。我们当时那个项目是一个典型的电商后台系统,早期就是一个大单体:几千个方法、几十张核心表、…

2026/10/16 3:32:05 阅读更多 →
论文AI率检测原理与降AI率实战技巧:从困惑度到人工改写

论文AI率检测原理与降AI率实战技巧:从困惑度到人工改写

1. 先搞清楚论文AI率到底在检测什么如果你最近写过论文、投过期刊,或者给导师交过开题报告,大概率已经见过某个查重报告上多出来一个叫“AI生成指数”的东西。我第一次看到的时候也懵,明明是自己一个字一个字写出来的,结果系统判了…

2026/10/16 3:32:05 阅读更多 →
Linux下海康监控视频QT demo源码:从拉流到上屏完整链路

Linux下海康监控视频QT demo源码:从拉流到上屏完整链路

简介:这份资源是面向Linux平台监控视频开发者的Qt示例工程源码,聚焦海康监控摄像头的视频流接入与播放场景,适合具备C基础、希望将Qt多媒体能力落地到安防监控项目的开发者参考。压缩包共220个文件,约1.2MB,以62个h头文…

2026/10/16 3:32:05 阅读更多 →
node-gyp 完全指南:原生模块构建从环境到排错

node-gyp 完全指南:原生模块构建从环境到排错

1. node-gyp 到底是什么,为什么装原生模块总在它手上翻车如果你在过去几年里用 Node.js 装过sharp、bcrypt、sqlite3、canvas这类带原生代码的依赖包,那大概率遇到过控制台里一串红字,其中高亮显示node-gyp这个名词。我第一次碰到时还挺懵的&…

2026/10/16 3:32:05 阅读更多 →
Flutter测试接入Jenkins:鸿蒙设备JUnit XML适配实录

Flutter测试接入Jenkins:鸿蒙设备JUnit XML适配实录

把 Flutter 测试结果接进 Jenkins,本来是一件很成熟的事:测试跑完,用 junitreport_maintained 把 flutter test 的 JSON 输出转成标准 JUnit XML,JUnit 插件解析 XML,趋势图、失败列表、历史对比全都有了。可当这批测试…

2026/10/16 3:31:04 阅读更多 →

日新闻

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 0:00:05 阅读更多 →
信号与系统频域分析作业解题指南

信号与系统频域分析作业解题指南

1. 作业背景与核心要求解析信号与系统作为电子信息类专业的核心基础课,其作业设计往往直接关联课程的核心知识框架。2026年春季第六次作业的布置,通常对应着课程进展到频域分析的关键阶段。根据常规教学进度推测,本次作业可能涉及以下核心内容…

2026/10/16 0:00:05 阅读更多 →
Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

1. 从一个"四不像"的练手项目说起如果你已经看完了Django的官方教程前几章,跟着敲完了投票应用,大概会有一种"我好像会了,又好像什么都不会"的割裂感。教程里每个知识点都是拆开的——这一章讲模型,下一章讲视…

2026/10/16 0:00:05 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/15 16:18:54 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/15 19:41:51 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 9:49:14 阅读更多 →