题目描述
You are given a list of integers x1, x2, . . . , xn and a number k. It is guaranteed that each i from 1 to k appears in the
list at least once.
Find the lexicographically smallest subsequence of x that contains each integer from 1 to k exactly once.
输入
The first line will contain two integers n and k, with 1 ≤ k ≤ n ≤ 200 000. The following n lines will each contain an integer xi with 1 ≤ xi ≤ k.
输出
Write out on one line, separated by spaces, the lexicographically smallest subsequence of x that has each integer from1 to k exactly once.
题目大意:给定两个整数n和k,下面n行给出n个数,这n个数中只包含1-k里面的数字,且每个数字至少出现一次。求一个字典序最小的子序列,包含1-k中所有的数字,当且仅当只出现一次。
分析:单调栈的应用,存储每个数字出现的次数(序列中有几个该数),从前往后遍历,遍历到一个数,就让这个数的个数减一。如果该数未出现在栈中,就与栈中第一个数进行比较,如果该数小于栈中第一个数,且此时第一个数的个数大于0,就让第一个数出栈,直到此时栈中第一个数大于该数或者栈中第一个数的个数等于0,停止操作,使该数入栈,以保证每个数都出现一次,且字典序最小。
详情见代码:
#include <bits/stdc++.h>
#define mod 11092019
using namespace std;
#define N 200001
int book[N];
int a[N];
int vis[N];
int cnt;
int main()
{
int n,l;
scanf("%d %d",&n,&l);
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
book[a[i]]++;//记数
vis[a[i]]=0;
}
stack<int>s;//设置栈
for(int i=1; i<=n; i++)
{
book[a[i]]--;
if(vis[a[i]]==1) continue;
while(!s.empty())
{
int top=s.top();
if(book[top]!=0)
{
if(top>a[i])
{
s.pop();
vis[top]=0;
}
else
{
break;
}
}
else
{
break;
}
}
s.push(a[i]);
vis[a[i]]=1;
}
cnt=0;
while(!s.empty())
{
a[cnt++]=s.top();
s.pop();
}
for(int i=cnt-1; i>=0; i--)
{
if(i==cnt-1)
{
cout<<a[i];
}
else
{
cout<<" "<<a[i];
}
}
return 0;
}