问题
问题描述
小蓝有一个长度为的数组, 初始时从左到右依次是 。 之后小蓝对这个数组进行了 次操作, 每次操作可能是以下 2 种之一:
- 左移, 即把移动到最左边。
- 右移, 即把移动到最右边。
请你回答经过次操作之后, 数组从左到右每个数是多少?
输入格式
第一行包含 2 个整数, 和 。 以下行每行一个操作, 其中“"表示左移,""表示右移.
输出格式
输出 个数, 代表操作后的数组。
5 3
L 3
L 2
R 1
样例输出
2 3 4 5 1
评测用例规模与约定
对于50%的评测用例, . 对于100%的评测用例, .
运行限制
最大运行时间:3s 最大运行内存: 512M
问题抽象:
这道题,每次需要将元素移动到第一位或者最后一位,很容易想到deque或者用vector进行操作,可以简化复杂度。样例给出的数据都是没有重复的,但是这个可以有重复的。刚开始我直接把最左和最右分开存,直接把最左的最后一位进行输出,还用哈希法对元素进行标记,后面发现最右的数组如果出现和最左相同的元素,直接鸡。所以,只能放在同个数组里,根据一个特殊的标记进行分类。现在就有两大问题:
- 重复的元素
- 左移与右移的操作 重复?直接上map。左移右移?map好像很难办?那就从value进行下手。第一次左移,把它放在第一位,后面咋办?从边界下手,让最左的边界-1.右边也一样。也就是说
int l=0,r=n+1;
if(turn l) map[n]=l; l--;
if(trun r) map[n]=r; r++;
后面根据value进行排序,就是答案。但是对map的排序可是又一小难点。
思路一:暴力枚举
如果不会map和map排序,直接暴力。
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+1;
vector<int>res;
void cao(char a,int n){
auto i=find(res.begin(),res.end(),n);
if(a=='L'){
res.insert(res.begin(),(*i));
i++;
res.erase(i);
}
else{
res.push_back((*i));
res.erase(i);
}
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;++i) res.push_back(i);
while(m--){
int x;
char f;
cin>>f>>x;
cao(f,x);
}
for(int i=0;i<res.size();++i) cout<<res[i]<<" ";
return 0;
}
算法复杂度o(n*m)~o(n^2)
数据量大一定爆。
思路二
map排序。。。
#include<bits/stdc++.h>
using namespace std;
bool cmp(const pair<int,int>a,pair<int,int>b){
return a.second<b.second;
}
int main(){
map<int,int>a;
int n,m;
cin>>n>>m;
int l=0,r=n+1;
for (int i = 1; i <= n; i++) a[i]=i;
while (m--)
{ char c;
int x;
getchar();
scanf("%c%d",&c,&x);
if(c=='L'){
a[x]=l;
l--;
}
else{
a[x]=r;
r++;
}
}
vector<pair<int,int>>v(a.begin(),a.end());
sort(v.begin(),v.end(),cmp);
for(auto i:v) cout<<i.first<<" ";
return 0;
}
总结:
这道题是2021年蓝桥杯的国赛题,没有考特定的算法,考的是对数据结构的应用。其他题解还有用链表的,数组模拟的。。。总之,对STL库常用的数据结构,一定要多熟悉。下面是map排序的步骤。
- 写一个排序cmp函数,让sort对value进行排序。
- 把map复制到vector中。map是一种关系映射结构,用pair<>进行替换非常合适。
vector<pair<string,int>>(map.begin(),map.end(),cmp)
- 直接sort。 pair和map的关系比较紧密,既然这样写不会报错,底层肯定相通的。STL的源码多读读可以发现新大陆!!!
更新:
重新做了一遍发现不用map也行,直接vector<pair<int,int>>,虽然用map和vector的时间开销差不多,但是多用了map空间,哈哈,小白一个!🤣