约瑟夫环问题多种解法
整理自原文
经典问题:
问题描述:编号为 1-N 的 N 个士兵围坐在一起形成一个圆圈,从编号为 1 的士兵开始依次报数(1,2,3…这样依次报),数到 m 的 士兵会被杀死出列,之后的士兵再从 1 开始报数。直到最后剩下一士兵,求这个士兵的编号。
使用循环链表
步骤:
1、先创建一个环形链表来存放元素。
2、然后一边遍历链表一遍删除,直到链表只剩下一个节点。
效率:
时间复杂度为 O(n * m), 空间复杂度是 O(n)。
代码: 简单代码,就不写了(太长)
数学解法
转
效率: O(n)
推理过程:
程序过程模拟:
对于数组[0, 1, 2, 3, 4],每次杀死第三位。为了模拟循环,数组写两遍。
第一轮是 [0, 1, 2, 3, 4, 0, 1, 2, 3, 4 ] 从 0 开始,2 被删除了。
第二轮是 [3, 4, 0, 1,3, 4, 0, 1 ] ,从 3 开始, 0 删除了。
第三轮是 [1, 3, 4,1, 3, 4 ],从 1 开始,4 删除了。
第四轮是 [1, 3,1, 3 ],从 1 开始,1 删除了。
最后剩下的数字是 [3]。
可以看到:每次都是固定地向前移位 m 个位置。
求解推理过程:
我们从最后剩下的 3 ,反向推这个数字在之前每个轮次的位置。
最后剩下的 3 的下标一定是 0。
第四轮反推,补上 m 个位置,然后模上当时的数组大小 2,位置是(0 + 3) % 2 = 1。
第三轮反推,补上 m 个位置,然后模上当时的数组大小 3,位置是(1 + 3) % 3 = 1。
第二轮反推,补上 m 个位置,然后模上当时的数组大小 4,位置是(1 + 3) % 4 = 0。
第一轮反推,补上 m 个位置,然后模上当时的数组大小 5,位置是(0 + 3) % 5 = 3。
所以最终剩下的数字的下标就是3。因为数组是从0开始的,所以最终的答案就是3。
总结一下反推的过程,就是
上轮num的下标 = (当前index + m) % 上一轮剩余数字的个数。
index是此轮过后的num下标。
理解2
.最后只剩下一个元素,假设这个最后存活的元素为 num, 这个元素最终的的下标一定是0 (因为最后只剩这一个元素),
所以如果我们可以推出上一轮次中这个num的下标,然后根据上一轮num的下标推断出上上一轮num的下标,
直到推断出元素个数为n的那一轮num的下标,那我们就可以根据这个下标获取到最终的元素了。推断过程如下:
首先最后一轮中num的下标一定是0, 这个是已知的。
那上一轮应该是有两个元素,此轮次中 num 的下标为 (0 + m)%n = (0+3)%2 = 1; 说明这一轮删除之前num的下标为1;
再上一轮应该有3个元素,此轮次中 num 的下标为 (1+3)%3 = 1;说明这一轮某元素被删除之前num的下标为1;
再上一轮应该有4个元素,此轮次中 num 的下标为 (1+3)%4 = 0;说明这一轮某元素被删除之前num的下标为0;
再上一轮应该有5个元素,此轮次中 num 的下标为 (0+3)%5 = 3;说明这一轮某元素被删除之前num的下标为3;
....
因为我们要删除的序列为0 ~ n-1,
所以求得下标其实就是求得了最终的结果。比如当n为5的时候,num的初始下标为3,所以num就是3,
代码:
for循环
如果是从0开始
class Solution { public int lastRemaining(int n, int m) { int ans = 0; // 最后一轮剩下2个人,所以从2开始反推 for (int i = 2; i <= n; i++) { ans = (ans + m) % i; } return ans; } }
如果是从1开始
#include <bits/stdc++.h> using namespace std; int main() { int n, m; cin>>n>>m; int ans=1; for(int i=2;i<=n;i++){ ans=(ans+m-1)%i+1; //cout<<ans<<endl; } cout<<ans<<endl; return 0; }
递归写法
int f1(int n, int m){ if(n == 1) return n; return (f(n - 1, m) + m - 1) % n + 1; } /************或者********/ int f2(int n, int m){ return n == 1 ? n : (f(n - 1, m) + m - 1) % n + 1; }
效率:
时间复杂度是 O(n),空间复杂度还是 O(n),因为会递归会调用 n 次。
本文作者:kingwzun
本文链接:https://www.cnblogs.com/kingwz/p/15664526.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步