Early Orders——单调栈

Early Orders
题目链接牛客竞赛:https://ac.nowcoder.com/acm/problem/218908

题目大意:

给你一个长度为n的数组,求其中一个字典序最小长度为k的子序列,并且此子序列中每个数只出现一次(即为1到k).

测试数据:
输入

6 3
3
2
1
3
1
3

输出

2 1 3

输入

10 5
5
4
3
2
1
4
1
1
5
5

输出

3 2 1 4 5

解题思路:

遍历这个数组,对每个数据判断是否入栈,让栈为从小到大的顺序(除非当前数字在队列中为最后一个则必须入栈),同时已经入过栈的数据不能再次入栈,最后的结果即为最终答案.

代码(带注释):

#include<iostream>

using namespace std;

const int N = 200010;
int map[N];//用来标记当前数据在整个数组中还剩下几个
int q[N];//记录数组数据
int list[N];//模拟栈
int flag;//指向栈顶位置
bool vis[N];//标记当前数据是否已经入栈

int main()
{
	int n, k;
	cin >> n >> k;
	//输入数组并且统计每个数据在数组中共出现几次
	for (int i = 0; i < n; i++)
	{
		cin >> q[i];
		map[q[i]]++;
	}
	//初始状态栈为空,无任何数据入栈
	for (int i = 1; i <= k; i++)
	{
		vis[i] = false;
	}
	//遍利数组
	for (int i = 0; i < n; i++)
	{
		int x = q[i];
		map[x]--;
		
		if (!vis[x])//判断是否已经入栈
		{
			while (x < list[flag] && map[list[flag]])//若栈顶大于当前数据且栈顶数据在之后还会出现则一直弹出栈顶
			{	
				vis[list[flag--]] = false;//取消栈顶已入栈标记,并且弹出栈顶
			}
			//当前数据入栈
			vis[x] = true;
			list[++flag] = x;
		}
	}
	//输出栈
	for (int i = 1; i <= k; i++)
	{
		cout << list[i] << " ";
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值