思路
需要解决两个问题:
- 如何实现将被淘汰的人从人群中删去,即此人不再参与报号
- 如何实现循环,即到达最后一个人之后,下次返回第一个人
数组
- 数组的每一个单元是不能删除的,只能通过做标记来表示这个位置的人被淘汰(如值等于-1表示这个位置的人被淘汰),但是这个空间并没有消失,每次遍历都还要遍历一下这些已经被淘汰的人的位置
- 比如说,有1000个人,淘汰到最后只剩下了2个人在相互报数,但是开辟的数组大小是1000,2人人报数时仍需要遍历这1000个数组空间,尽管数组中其他位置的人已经被淘汰了,这样会导致超时
- 我们希望能将这些淘汰的位置彻底删除,而不是继续留在结构中,每次都要访问
链表 list
- 数组的单元是没法删除的,但是链表的结点是可以删除的,因此对于淘汰的人,不是将其值赋值为-1,而是将其结点删除
- 链表 list 的相关操作:
#include<list> //头文件
list<int> l; //构建一个空链表
for(int i = 1; i <= n; ++i) //依次从尾部插入n个结点,值分别为1、2、3……
l.push_back(i);
list<int>::iterator it = l.begin(); //链表的迭代器
//删除it指向结点,并
list<int>::iterator temp = it;
it++;
l.erase(temp);
//it超出了范围,返回第一个
if(it == l.end())
it = l.begin();
cout << *it << endl; //输出迭代器对应的元素值
- 注意begin()是第一个数据结点,end()是最后一个数据结点之后的结点(无数据),如果 it 等于end(),则说明已跑到了最后一个人的后面,需要返回第一个人
- 代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<list>
using namespace std;
int main()
{
int n, k;
list<int> l;
cin >> n >> k;
for(int i = 1; i <= n; ++i)
l.push_back(i);
list<int>::iterator it = l.begin();
int num = 0;
while(l.size() > 1)
{
num++;
if(num % k == 0 || num % 10 == k)
{
list<int>::iterator temp = it;
it++;
l.erase(temp);
}
else
it++;
if(it == l.end())
it = l.begin();
}
cout << *it << endl;
return 0;
}
队列 queue
- 队列是一段入,另一端出
- 报数的思路是:队首到队尾依次是1、2、3……n,每次报数的同时出队,如果没有被淘汰,则重新入队(到队尾),如果被淘汰了,那就不用管了
- 队列 queue 的相关操作:
#include<queue> //头文件
queue<int> q; //构建一个空队列
//插入元素,队首到队尾依次是1、2、3……n
for(int i = 1; i <= n; ++i)
q.push(i);
int a = q.front(); //获取队首元素值
q.pop(); //队首出队
q.push(a); //入队
- 代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int main()
{
int n, k;
queue<int> q;
cin >> n >> k;
for(int i = 1; i <= n; ++i)
q.push(i);
int num = 0;
while(q.size() > 1)
{
num++;
if(num % k == 0 || num % 10 == k)
{
q.pop();
}
else
{
int a = q.front();
q.pop();
q.push(a);
}
}
cout << q.front() << endl;
return 0;
}
对比
- 数组的思想是比较好想的,但是任意超时
- 链表的思想和数组方式很相近,但是链表里面涉及迭代器,不是很好操作
- 队列代码和思路比较简单,但是里面出队入队的思路不任意通过题目题意想到,题目题意想到的一般是数组或者链表的做法
- 分别用链表和队列交了两次,下面是 list,上面是 queue,发现队列的速度更快,可能是由于 list 的删除操作的复杂度不是O(1),导致慢一点