鏈接:https://ac.nowcoder.com/acm/contest/551/D
來源:牛客網
題目描述
CSL 以前不會字符串算法,經過一年的訓練,他還是不會……於是他打算向你求助。
給定一個字符串,只含有可打印字符,通過刪除若干字符得到新字符串,新字符串必須滿足兩個條件:
- 原字符串中出現的字符,新字符串也必須包含。
- 新字符串中所有的字符均不相同。
- 新字符串的字典序是滿足上面兩個條件的最小的字符串。
輸入描述:
僅一行,有一個只含有可打印字符的字符串 s。
|s|≤105|s|≤105
輸出描述:
在一行輸出字典序最小的新字符串。
示例1
輸入
bab
輸出
ab
示例2
輸入
baca
輸出
bac
備註:
ASCII字符集包含 94 個可打印字符(0x21 - 0x7E),不包含空格。
思路:使用棧進行模擬,如果當前字符已經在棧中,則跳過(保證了每個字符只存一次),否則進行如下操作:如果當前字符比棧頂元素小並且棧頂元素在之後的序列中仍有剩餘,就彈出棧頂元素,持續這個過程直到棧頂元素比當前元素小或者棧頂元素沒有剩餘,然後把當前字符放入棧中(保證了所有字符都會存入棧中)
以上思路來源於https://blog.csdn.net/Septembre_/article/details/88942986
舉個例子:字符串dbdcebhgdac!ad 模擬一下過程:
1. 開始棧爲空,放入d.此時棧裏(下面也都是從棧底到棧頂來說的)有d
2. b比棧頂小,而且d在後面出現,所以刪掉d,把b放入,此時棧裏有b
3.d比棧頂大,直接放入,此時棧裏有bd
4.c比棧頂小,而且d在後面出現,所以刪掉d,把c放入,此時棧裏有bc
5.e比棧頂大,直接放入,此時棧裏有bce
6.b棧裏面有,直接跳過不用管,此時棧裏有bce
7.h比棧頂大,直接放入,此時棧裏有bceh
8.g比棧頂大,直接放入,此時棧裏有bcehg
9.d比棧頂小,但是棧頂元素在接下來的字符串中沒有出現過,所以直接放入d,此時棧裏有bcehgd
10.a比棧頂小,而且d在後面出現,所以刪掉d,把a放入,此時棧裏有bcehga
11.c棧裏面有,直接跳過不用管,此時棧裏有bcehga
12.!比棧頂小,而且a在後面出現.所以刪掉a,把!放入,此時棧裏有bcehg!
13.a比棧頂大,直接放入,此時棧裏有bcehg!a
14.d比棧頂大,直接放入,此時棧裏有bcehg!ad
所以最後應該輸出bcehg!ad(注意從棧底往棧頂輸出,可用遞歸)
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <deque>
#include <queue>
#include <stack>
#include <set>
using namespace std;
typedef long long ll;
const int MAX=998244353;
const int M=1e5+7;
stack <char> st;
void f()
{
if(st.empty())
{
return ;
}
char c=st.top();
st.pop();
f();
cout<<c;
}
int main()
{
string s;
ll i,j,flag[200]={0},len;
cin>>s;
len=s.size();
for(i=0;i<len;i++)
{
flag[s[i]]++;//標記接下來的字符出現的個數
}
char vis[200]={0};//標記字符是否在棧中
for(i=0;i<len;i++)
{
flag[s[i]]--;
if(vis[s[i]]==0)
{
vis[s[i]]=1;
while(!st.empty()&&s[i]<st.top()&&flag[st.top()]!=0)
{
vis[st.top()]=0;
st.pop();
}
st.push(s[i]);
}
}
//從下往上輸出
f();
cout<<endl;
return 0;
}