题目描述:
0,1,···,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字(删除后从下一个数字开始计数)。求出这个圆圈里剩下的最后一个数字。
例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。
示例 1:
输入: n = 5, m = 3
输出: 3
示例 2:输入: n = 10, m = 17
输出: 2
限制:
1 <= n <= 10^5
1 <= m <= 10^6来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
分析:
对不起,我错了。我不该轻视这道题的,第一眼看到这题,总觉得哪里见过,但始终想不起来,但我也没多想,就直接模拟法做了。先后试了用数组模拟,用vector模拟,都超时了,我不信邪,数组删除元素后要移动,需要O(n)的复杂度,那链表总不用吧?链表删除并不麻烦,于是又用链表进行模拟,事实证明我太年轻了,又超时了。
代码分别如下(不用看了,都会超时,只是记录一下)
数组模拟:
class Solution {
public:
int lastRemaining(int n, int m) {
int num[n];
bool flag[n];
for(int i=0;i<n;i++)
{
num[i]=i;
flag[i]=true;
}
int k=0;
int all=0;
for(int i=0;all<n-1;)
{
// cout<<" i is "<<i<<" k is "<<k<<endl;
if(flag[i])
k++;
if(k==m)
{
// cout<<i<<endl;
flag[i]=false;
all++;
// i++;
k=0;
}
i++;
if(i>n-1)
i=0;
}
for(int i=0;i<n;i++)
if(flag[i]) return i;
return 0;
}
};
vector模拟
class Solution {
public:
int lastRemaining(int n, int m) {
vector<int> num(n);
for(int i=0;i<n;i++)
num[i]=i;
int k=0;
int all=0;
for(auto it=num.begin();all<n-1;)
{
k++;
if(k==m)
{
all++;
k=0;
num.erase(it);
if(it>=num.end())
it=num.begin();
continue;
}
it++;
if(it>=num.end())
it=num.begin();
}
return num[0];
}
};
链表模拟
class Solution {
public:
typedef struct node{
int val;
struct node *next;
node(int val):val(val),next(NULL){};
};
int lastRemaining(int n, int m) {
node *head=new node(0);
node *p=head;
int k=1;
while(k<n)
{
node *temp=new node(k);
p->next=temp;
p=p->next;
k++;
}
p->next=head;
int len=n;
int tempm=m;
if(m>len)
tempm=m%len;
int step=0;
int all=0;
node *pre=p;
p=head;
while(all<n-1)
{
step++;
if(step>=tempm)
{
pre->next=p->next;
len--;
if(m>len)
tempm=m%len;
if(tempm==0)
tempm=len;
p=p->next;
all++;
step=0;
continue;
}
p=p->next;
pre=pre->next;
}
return p->val;
}
};
怀着一股忿忿不平之气,打开题解,这TM是啥,我立马怂了,果然没有那么简单,还是一道动态规划。说实话,我真的一点儿也没有想到它是动态规划题。。。。。
题解很多,写得也很花,各路大神云集,眼花缭乱,可惜我看不懂
唯二能看懂的两篇,附上链接:
果然,我的智商只有胎教水平。。。。。
实际上只有三行。。。。真的是羞辱+讽刺,还是要多写题啊。。。
代码如下:
class Solution {
public:
int lastRemaining(int n, int m) {
// n=1的时候,无论m为多少,最终剩下的那个数始终是0(即唯一的那个数)
int res=0;
// i从2开始,依次增加到n,按照递推公式求解
for(int i=2;i<=n;i++)
res=(res+m)%i;
// 返回最终结果
return res;
}
};
注意,链表的定义和构造函数示例:
struct node{
int data;
string str;
char x;
//注意构造函数最后这里没有分号哦!
node() :x(), str(), data(){} //无参数的构造函数数组初始化时调用
node(int a, string b, char c) :data(a), str(b), x(c){}//有参构造
}N[10];