约瑟夫环是一个经典的递归问题。以前没有太过于注意,今天刷到了,竟然没有想到递归的解法,只想到模拟的解法,故提笔记之
题目如下
第一种解法。模拟
用一个标记数组标记已经淘汰掉的小伙伴,知道剩余一位
class Solution {
public:
int findTheWinner(int n, int k) {
vector<int> tags(n, 0);
/*将1-n编号为0-n-1*/
int start = 0;
int cnt = n;
while(cnt>1){
int t = 0;
do{
if(tags[start]==0){
t++;
}
if(t==k){
tags[start] = 1;
cnt--;
}
start=(start+1)%n;
while(tags[start]){
start=(start+1)%n;
}
}while(t<k);
}
return start+1;
}
};
利用队列模拟
刚才是朴素模拟,我们还可以用一个数据结构队列进行优化
class Solution {
public:
int findTheWinner(int n, int k) {
queue<int> qu;
for(int i=1;i<=n;i++){
qu.push(i);
}
while(qu.size()>1){
for(int i=0;i<k-1;i++){
qu.push(qu.front());
qu.pop();
}
qu.pop();
}
return qu.front();
}
};
递归解法
每次往同一方向,以固定步长 k 进行消数。由于下一次操作的发起点为消除位置的下一个点(即前后两次操作发起点在原序列下标中相差 k),同时问题规模会从 n 变为 n−1,因此原问题答案等价于 findTheWinner(n - 1, k) + k。
class Solution {
public:
int findTheWinner(int n, int k) {
//递归思路
if(n==1){
return 1;
}
int ans = (findTheWinner(n-1, k)+k)%n;
return ans==0? n: ans;
}
};
迭代解法
我们对递归解法稍微分析一下,就可以得到其迭代解法
class Solution {
public:
int findTheWinner(int n, int k) {
/*改成迭代*/
int ans = 1;
for(int i=2;i<=n;i++){
ans = (ans+k)%i;
ans = ans==0?i:ans;
}
return ans==0?n: ans;
}
};