左移右移(数据结构)

43 阅读2分钟

问题

问题描述

小蓝有一个长度为NN的数组, 初始时从左到右依次是 1,2,3,N1,2,3,…N。 之后小蓝对这个数组进行了 MM次操作, 每次操作可能是以下 2 种之一:

  1. 左移xx, 即把xx移动到最左边。
  2. 右移xx, 即把xx移动到最右边。

请你回答经过MM次操作之后, 数组从左到右每个数是多少?

输入格式

第一行包含 2 个整数, NNMM 。 以下MM行每行一个操作, 其中“LxLx"表示左移xx,"RxRx"表示右移xx.

输出格式

输出 NN个数, 代表操作后的数组。

5 3
L 3
L 2
R 1

样例输出

2 3 4 5 1

评测用例规模与约定

对于50%的评测用例, 1N,M100001≤N,M≤10000. 对于100%的评测用例, 1N,M200000,1xN1≤N,M≤200000,1≤x≤N.

运行限制

最大运行时间: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排序的步骤。

  1. 写一个排序cmp函数,让sort对value进行排序。
  2. 把map复制到vector中。map是一种关系映射结构,用pair<>进行替换非常合适。vector<pair<string,int>>(map.begin(),map.end(),cmp)
  3. 直接sort。 pair和map的关系比较紧密,既然这样写不会报错,底层肯定相通的。STL的源码多读读可以发现新大陆!!!

更新:

重新做了一遍发现不用map也行,直接vector<pair<int,int>>,虽然用map和vector的时间开销差不多,但是多用了map空间,哈哈,小白一个!🤣