方法1:思路简单,速度很慢;

思路比较简单,完全按照题目的意思翻译成程序,必要的注释已经给出;一个元素一个元素向后,到达尾部就返回去;每次访问到的元素都进行了标记,并且下次访问时直接跳过,只对有效的(未被标记的)元素进行计数;算法的缺点就是:浪费太多时间。

//程序运行的是真的慢
class Solution {
public:
int LastRemaining_Solution(int n, int m)
{
if(n == 0)
return -1;
int count = m; //计数
int restore[n];
for(int i = 0;i<n;++i)
restore[i] = i; //先将所有的元素暂存在数组中
vector<int> res(n); //开辟空数组,对路径进行记录,只需输出最后一个元素即可
int j = 0;
for(int i = 0;i < n; ++i)
{
if(restore[i] == -2) //被标记的元素就跳过
{
if(i == n-1)
i = -1; //这两行在尾元素标记时起作用,用以回到数组起始位置
continue;
}
count--;
if(count == 0) //跳过被标记的,遍历数目达到,就可以放入数组中了
{
res[j++] = i;
if(j == n)
break;
restore[i] = -2; //访问过就标记,保证不会重复访问
count = m;
}
if(i == n-1)
i = -1; //这两行是尾元素未被标记时起作用,用以回到数组起始位置
}
return res[n-1];
}
};
方法2:使用标准库容器,符合逻辑的思维,直观而简单
标准库的容器帮我们解决了头疼的元素数量逐渐变少的问题;取余运算符又解决了头疼的圈圈问题;而且k值的步进保持不变;记住:循环加等步进 == 取余;代码如下:
//程序运行的是真的慢
class Solution {
public:
int LastRemaining_Solution(int n, int m)
{
if(n ==0)
return -1;
vector<int> res;
for (int i = 0; i < n; ++i)
{
res.push_back(i); //先把元素都装进来
}
int k = 0;
while (res.size() > 1)
{
k = (k + m -1) % res.size(); //保持相同的间隔一直向后;取余实现了圈圈(想想循环队列)
res.erase(res.begin()+k); //把这个孩子赶出去,size相应减小1
}
return res[0];
}
};
方法3:头疼法
建议跳过
class Solution {
public:
int LastRemaining_Solution(int n, int m)
{
if(n == 0)
return -1;
int last=0;
for(int i=2;i<=n;i++){
last=(last+m)%i;
}
return last;
}
};</int></int>