代码源:608、字典序最小

427 阅读1分钟

本文已参与[新人创作礼]活动,一起开启掘金创作之路 logo.png

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

题目描述

这是3月22日代码源div2的每日一题。

知识点:单调栈

字典序最小 - 题目 - Daimayuan Online Judge

从序列 M 个数中顺序选出 N 个不同的数, 使得这 N 个数的字典序最小。

输入格式

第一行两个整数 M, N分别表示序列长度,顺序选取数据的个数 (其中1<N≤M≤10^6)。

接下来 M 行,第 i 行输入为第 ai,表示序列 M 中第i 个数,其中 1≤ai≤N, 数据保证 [1,N] 范围内每个数至少出现一次。

输出格式

输出 N 个数, 用空格隔开, 表示最小字典序 (最后一个输出不能有多余空格)。

样例输入

6 3
3
2
1
3
1
3

样例输出

2 1 3

题目说明

求解的最小字典序不必在序列 M 中连续。

问题分析

这题我们想要得到最小的字典序,那前面的数都要尽可能小,随着遍历数组我们要更新更小的元素,同时把大的元素从记录的序列中移除,这一性质就很适合我们单调栈。

我们先预处理一下,用一个数组f先记录每个数的出现次数,然后用一个栈遍历数组,每遍历到一个数,数组f里这个数的出现次数--,如果栈为空,就把遍历到的元素入栈,并且用一个数组记录当前栈内的元素;如果栈不为空,而且当前元素没有在栈内,就用当前元素和栈顶元素比较一下,如果栈顶元素在数组的出现次数不为0(数组后面还会出现),就把这个元素出栈,然后继续用当前元素和新的栈顶元素对比,直到新的栈顶元素在数组后面不再出现(如果此时再删,那这个数就永远丢失了),或者栈顶元素小于当前元素是停止出栈,把元素入栈。如果一开始当前元素已经在栈内了,那就不用进行出栈操作(我们出栈是为了把小的数尽可能放前面,既然这个元素已经有在栈内了就不用在出栈了),最后把栈内元素反向输出就行。

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")

#define endl '\n';
typedef long long ll;
typedef pair<ll, ll>PII;
const int N = 1e6 + 50;

int f[N];

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int n,m;
    cin >> n >> m;
    vector<int>v(n),mymap(N+1);
    for (int i = 0; i < n; i++)
    {
        cin >> v[i];
        f[v[i]]++;
    }
    stack<int>sta;
    sta.push(v[0]);
    f[v[0]]--;
    mymap[v[0]] = 1;
    for (int i = 1; i < n; i++)
    {
        while (!sta.empty() && sta.top() > v[i] && f[sta.top()] > 0 && mymap[v[i]] != 1)
        {
            mymap[sta.top()] = 0;
            sta.pop();
            
        }
        if (mymap[v[i]] == 0)
        {
            sta.push(v[i]);
            mymap[v[i]] = 1;
        }
        f[v[i]]--;
    }
    vector<int>res;
    while (!sta.empty())
    {
        res.push_back(sta.top());
        sta.pop();
    }
    cout << res[m - 1];
    for (int i = m - 2; i >= 0; i--)cout << " " << res[i] ;
    return 0;
}