题目:环形链表的约瑟夫问题
描述:编号为1到n的n个人围成一圈。从编号为1的人开始报数,报到m的人离开。下一个人继续从1开始报数。n−1轮结束以后,只剩下一个人,问最后留下的这个人编号是多少?
示例1:输入:5,2,返回值:3
说明:开始5个人1,2,3,4,5,从1开始报数,1->1,2->2编号为2的人离开
1,3,4,5,从3开始报数,3->1,4->2编号为4的人离开
1,3,5,从5开始报数,5->1,1->2编号为1的人离开
3,5,从3开始报数,3->1,5->2编号为5的人离开
最后留下人的编号是3
解法一:
举例分析+思路分析:约瑟夫环是一个经典的数学问题,如果我们按照规律进行依次报数的话会发现有一个递推公式,下面,我们使用表格进行解释,假设有5个人,第2个人会离开
经过第一次,发现数字2离开了,剩余的人数变为4
第二次循环,数字4离开了,剩余的人数变为3
第三次循环,数字1离开了,剩余的人数变为2
最后一次,数字5离开了,剩余的人数变为1
最终留下的人的编号为3。
我们得到一个大致的递推公式为:,
表示N个人中第M个离开,
表示N-1个人中第M个离开,根据上表,我们可以得到一个大致的逻辑就是,当有两个人的时候,没有离开的人的序号为0(假设序号是从0开始的),当有三个人的时候,没有离开的人的序号为2,当有四个人的时候,没有离开的人的序号为0……以此类推,便可以通过公式法将最终的结果反推出来,具体公式为
,res的初始值为0。由此可以直接编写代码。
C++核心代码为:
class Solution {
public:
/**
*
* @param n int整型
* @param m int整型
* @return int整型
*/
int ysf(int n, int m) {
// write code here
int res = 0;
for(int i = 2;i <= n;i++){
res = (res + m) % i;//从2 开始进行推导
}
return res + 1;
}
};该方法直接采用数学公式法进行推导,所以时间复杂度为,没有用到额外的内存空间,空间复杂度为
。
解法二:
思路分析:我们也可以建立一个单链表对象,首先将所有的值都添加到单链表当中,其次可以不断的判断单链表的大小值,通过设定一个index对象,刚开始赋值为0,只要对单链表大小进行不断取余,然后删除,就可以找到最后一个值的位置。
实例分析:
首先令,
;,根据判断出局第一个元素为2,序号为1。
其次出局的元素为4,序号为3。
然后出局的元素为1,序号为0。
最后出局的元素为5,序号为4。
java核心程序为:
import java.util.*;
public class Solution {
/**
*
* @param n int整型
* @param m int整型
* @return int整型
*/
public int ysf (int n, int m) {
// write code here
ArrayList<Integer> res = new ArrayList<>();
for(int i = 1;i <= n;i++){
res.add(i);//将n个人添加到链表中
}
int index = 0;
while(res.size() > 1){
index = (index + m - 1) % res.size();//判断删除的链表结点
res.remove(index);//删除
}
return res.get(0);
}
};该算法需要遍历所有的元素,所以时间复杂度为,需要新建一个单链表对象,用于存放元素结点,所以其空间复杂度为
。

京公网安备 11010502036488号