剑指Offer-62-圆圈中最后剩下的数字
约瑟夫环问题
已知 n 个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围。从编号为 k 的人开始报数,数到 m 的那个人出圈;他的下一个人又从 1 开始报数,数到 m 的那个人又出圈;依此规律重复下去,直到剩余最后一个胜利者。
递归
假设f(n,m)
代表从长度为n的序列中,循环数到m就划掉,最终剩下来的元素
第一次划掉的元素应该就是第m个,但是因为m可能大于n,所以要取模
那么递归公式就是f(n,m)=m%n+f(n-1,m)
,即长度为n-1的序列中剩下的那个位置元素,再偏移我们第一次删除的位置(因为是接着重新数的)
当然,这个结果也可能会大于n,所以要模n
递归这个过程,当序列长度为1是,留下唯一的元素(下标为0)
class 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; } }; int main() { Solution s; cout << s.lastRemaining(10, 17); return 0; }
时间复杂度O(n)
:需要求解n个函数值
空间复杂度O(n)
:递归深度n,需要O(n)
的栈空间
迭代写法
class Solution { public: int lastRemaining(int n, int m) { // 可以看作是自底向上推,长度为1已经知道了,返回下标为0 int f = 0; // 一共有n个结果,去掉一个知道的,循环n-1次 // 但是这里i的初值必须注意…为什么初始是2…或者说:%i怎么理解? for (int i = 2; i <= n; ++i) f = (m + f) % i; return f; } };
模拟
模拟分 原始的循环链表模拟 和 有序数组模拟
说模拟会超时
本文作者:YaosGHC
本文链接:https://www.cnblogs.com/yaocy/p/16591635.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步