题目描述
栗酱有一天在网上冲浪的时候发现了一道很有意思的数据结构题。
该数据结构形如长条形。
一开始该容器为空,有以下七种操作。
1 从前面插入元素a
2 从前面删除一个元素
3 从后面插入一个元素
4 从后面删除一个元素
5 将整个容器头尾翻转
6 输出个数和所有元素
7 对所有元素进行从小到大排序
输入描述:
只有一组数据,第一行n≤50000,m≤200000, a≤100000 代表最大数据数目和操作次数。
接下来每一行一个操作如上描述。保证所有操作合法(不会在容器为空时删除元素)。
6、7操作共计不会超过10次。
输出描述:
当执行6操作时,第一行先输出当前的个数,然后从头到尾按顺序输出,每两个元素之间用一个空格隔开,末尾不能有空格。
示例1
输入
10 9
1 1
3 5
3 4
6
4
5
6
7
6
输出
3
1 5 4
2
5 1
2
1 5
deque题解
PS: 刚刚看到这个题目的时候我第一想到的就是双向队列,因为这个题目就是一个deque的模板题,奈何当时对deque不是很熟悉,之前只遇到过一次,但是这个打算详细说一下,并且记录一下
1.deque就是一个两头操作的队列。
2.有头插,尾插:push_front()/push_back()。
3.有头删,尾删:pop_front()/pop_back()。
4.然后再用一些工作性算法:sort(排序),reverse(倒置)。
接下来就是一个显而易见的代码了
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
char c[maxn];
deque<int> q;
int main()
{
int n, m, x, y;
scanf("%d%d", &n, &m);
while (m--)
{
scanf("%d", &x);
{
if (x == 1)
{
scanf("%d", &y);
q.push_front(y);
}
else if (x == 2)
q.pop_front();
else if (x == 3)
{
scanf("%d", &y);
q.push_back(y);
}
else if (x == 4)
q.pop_back();
else if (x == 5)
reverse(q.begin(), q.end());
else if (x == 6)
{
printf("%d\n", q.size());
for (int i = 0; i < q.size(); ++i)
printf("%d ", q[i]);
puts("");
}
else
sort(q.begin(), q.end());
}
}
}
vector题解
不得不说vector的功能是在太强大!!!
vector首先它是一个动态数组也就是我们口头的“会变长的数组”,如果你定义了一个vector数组,但是题目给的数据以及超过了这个范围,怎么办?这时候不用担心了,vector会自己变长,他首先会开辟一个是之前两倍的新的空间,然后把之前的数据复制一遍,然后在多的空间继续填空。
vector的下标默认是从零开始的!!,并且它的默认删除和插入都是对开头进行操作
上代码
#include <bits/stdc++.h>
using namespace std;
vector<int> v;
int main()
{
int n, m, op, x;
scanf("%d%d", &n, &m);
while (m--)
{
scanf("%d", &op);
if (op == 1)
scanf("%d", &x), v.insert(v.begin(), x);
else if (op == 2)
v.erase(v.begin());
else if (op == 3)
scanf("%d", &x), v.push_back(x);
else if (op == 4)
v.pop_back();
else if (op == 5)
reverse(v.begin(), v.end());
else if (op == 7)
sort(v.begin(), v.end());
else
{
printf("%d\n", v.size());
for (auto it = v.begin(); it != v.end(); ++it) //auto是一个可以识别变量类型的一种类型
printf("%d ", *it); //因为在数组里面存的都是元素的地址,在地址前面加个*就代表当前数组元素的值
puts("");
}
}
return 0;
}
数组模拟题解
数组模拟是我没想到的,而且这个模拟处理的很巧妙,从中间开始慢慢填数
数组开两倍(因为如果一直从前插入从0开始下标就是负数了,数组会越界),然后双指针,l记录头的位置,r记录尾的位置,因为排序不超过十次,所以sort(nlogn)不会超时的。
最开始l在2e5的位置(只要数组够大,l再往后一些也是可以的),r=l;
模拟以下操作
1.a从前面插入元素(就是a[–l]=x,如果r=l+1的话,就可以用a[l–]=x);
2.从前面删除一个元素(++l就相当于删掉最前面的元素);
3.a从后面插入一个元素(就是a[r++]=x);
4.从后面删除一个元素(r–就相当于删掉最后面的元素);
5.将整个容器头尾翻转 ,reverse(a+l,a+r);
6.输出个数和所有元素 (遍历数组下标l到r输出就好了);
7.对所有元素进行从小到大排序,sort(a+l,a+r);
代码
#include <bits/stdc++.h>
using namespace std;
int a[400100];
int main()
{
int l = 200001, r = 200001;
int n, m, x, y;
scanf("%d%d", &n, &m);
while (m--)
{
scanf("%d", &x);
if (x == 1)
{
scanf("%d", &y);
a[--l] = y;
}
else if (x == 2)
l++;
else if (x == 3)
{
scanf("%d", &y);
a[r++] = y;
}
else if (x == 4)
r--;
else if (x == 5)
reverse(a + l, a + r);
else if (x == 6)
{
printf("%d\n", r - l);
for (int i = l; i < r; i++) //这里说明一下,r这个位置为什么不可取,因为在数组里面++,--在前面是先进行运行的,在外面不管在前面和后面效果都是一样的
//因为刚开始从左边放入一个数就是--在变量前面,所以数组左下标在赋值之前已经移动了,而++在变量后面,这下操作是在赋完值后才移动的,所以数组右边界不会到r,而是r-1
printf("%d ", a[i]);
puts("");
}
else
sort(a + l, a + r);
}
return 0;
}
反抗你的敌人需要过人的勇气,而在朋友面前坚持自己的立场需要更大的勇气。坚持自己的观点,不因友情而却步,这是真正的勇者,也是对待友情的正确态度 |
---|