题目描述
0, 1, …, n-1这n个数字(n>0)排成一个圆圈,从数字0开始每次从这个圆圈里删除第m个数字。
求出这个圆圈里剩下的最后一个数字。
输入样例:
n=5 , m=3
输出样例:
3
解题报告
题意理解
这道题首先是从 0 - n 的数字组成一个环,每次从中拿出一个数字,看最后剩下的数字是谁
算法处理
算法一:写一个链表,模拟去除的过程
算法二:
发现数学规律,求递推公式
我们假设 m = 3
并且当 n = 1 时, f(n,m) = 0(幸存者下标)
当 n = 2时,f(2,3) = (f(1,3)+3)%2 = 3%2 = 1
可能有人会问,为什么 n =2 时是这个式子
假设 n , m 时,则被杀的是(m-1)%n,令其等于k
则 n-1,m时,(0,1,…,k-1,k+1,…,n-1)此时从,k+1作第0个,相当于 n 个人时,向右移动 所以 f(n-1,m) = (f(n,m) - m)%(n-1)
那从 n -1到 n,就有 f(n,m) = (f(n-1,m)+m)%n 逆映射
f(n,m) = (f(n-1,m)+m)%n
代码实现
方法一:
#include <list>
class Solution {
public:
int lastRemaining(int n, int m){
list<int> nums;
cin >> n >> m;
for(int i=0;i<n;i++) nums.push_back(i);
auto it = nums.begin();
int k = m -1;
while(nums.size()>1){
while(k--){
it++;
if(it==nums.end()) it = nums.begin();
}
it = nums.erase(it); //删除第m个元素;
if (it == nums.end()) it = nums.begin();
k = m - 1;
}
return nums.front();
}
};
方法二:
class Solution {
public:
int lastRemaining(int n, int m){
int p = 0; //因为数组是从 0 开始的
for(int i=2;i<=n;i++){
p = (p+m)%i; //递推
}
return p;
}
};