一、问题描述:
二、解题分析:
1.方法一: 环形链表
拿到这个题,我就在想可以用环形链表来实现,可是我一查STL 好像无环形链表··
STL 中的list是双向循环链表,并不是环形结构,所以可以当指针指向链表尾部的时候,下一步指向链表首部。
按照这种方法就可以写出了
class Solution {
public:
int lastRemaining(int n, int m) {
//环形链表
list<int> numbers;
for(int i=0;i<n;i++){
numbers.push_back(i);
}
auto cur=numbers.begin();
while(numbers.size()>1)
{
//找到要删除的数字
for(int i=1;i<m;i++)
{
cur++;
if(cur==numbers.end())
{
cur=numbers.begin();
}
}
//找到了要删除的数字,设置一个next保存cur的后一位
auto next=++cur;
if(cur==numbers.end()){
next=numbers.begin();
}
cur--;
numbers.erase(cur);//erase()删除容器中某个元素
cur=next;
}
return *(cur);//取出指针的值
}
};
但是辛辛苦苦写出来的代码却 超时了!!!
于是好好分析一下,首先需要存储0~n-1个数字,需要的空间复杂度是
O
(
n
)
O(n)
O(n).
每删除一个数字需要走m步,一共有n个数字。所以时间复杂度
O
(
m
n
)
.
O(mn).
O(mn).
2.方法二:数学公式推导
来源:LeetCode题解
这个题其实是一个约瑟夫问题,这个问题描述是:
N个人围成一圈,第一个人从1开始报数,报M的将被杀掉,下一个人接着从1开始报。如此反复,最后剩下一个,求最后的胜利者。
然后可以得到递推公式:
这样代码很容易写完了。
class Solution {
public:
int lastRemaining(int n, int m) {
if(n==1){
return 0;
}
return (lastRemaining(n-1,m)+m)%n;
}
};
时间复杂度为 O ( n ) O(n) O(n)