链接:https://ac.nowcoder.com/acm/contest/551/D
来源:牛客网
CSL 以前不会字符串算法,经过一年的训练,他还是不会……于是他打算向你求助。
给定一个字符串,只含有可打印字符,通过删除若干字符得到新字符串,新字符串必须满足两个条件:
- 原字符串中出现的字符,新字符串也必须包含。
- 新字符串中所有的字符均不相同。
- 新字符串的字典序是满足上面两个条件的最小的字符串。
输入描述:
仅一行,有一个只含有可打印字符的字符串 s。
|s|≤105|s|≤105
输出描述:
在一行输出字典序最小的新字符串。
示例1
输入
复制
bab
输出
复制
ab
示例2
输入
复制
baca
输出
复制
bac
备注:
ASCII字符集包含 94 个可打印字符(0x21 - 0x7E),不包含空格。
先放出代码:
#include<iostream>
using namespace std;
#include<bits/stdc++.h>
const int maxn=100005;
typedef long long ll;
int vis[maxn];
int used[maxn];
int main()
{
string s;
cin>>s;
stack<char>v;
for(int i=0;i<s.length();i++)
{
used[ s[i] ]++;
}
vis[ s[0] ]=1;
used[ s[0] ]--;
v.push(s[0]);
for(int i=1;i<s.length();i++)
{
used[ s[i] ]--;
if(vis[s[i]]==0)
{
while(!v.empty()&&v.top()>s[i]&&used[ v.top() ])
{
char c=v.top();
vis[c]=0;
v.pop();
}
v.push( s[i] );
vis[s[i]]=1;
}
}
string ans;
while(!v.empty())
{
ans+=v.top();
v.pop();
}
reverse(ans.begin(),ans.end());
cout<<ans<<endl;
return 0;
}
一开始不知道怎么来模拟这个字符串,需要将多个字符化为删除 成为一个,并且使最后的字典序最小,一开始并不知道怎么来模拟。最后看了大神的代码。思路是 先是将各种字符计数 ,然后用单调有序栈来存字符,字典序最小。1.如果当前栈顶的元素比要加进来的元素字典序小(假定这个栈顶字符出现数大于2,是要删除的字符),我们就不能把这个删除,那么后面的再出现这个字符,我们就得将这个删除掉;2.如果栈顶元素比要加进来的字符字典序大,我们就要将目前栈顶元素pop 掉,使字典序小一些。这样的话,我们在以后继续遇见这个字符,我们还需要 加进来(一种字符只能留一个,不能多,也不能少)。 上面的这两个情况操作我们需要一个标记数组来进行标记,看看是 第几种情况 1 还是 2,我们都需要进行标记,判断如果是第一种情况,我们后面再遇见这个字符,我们这个标记数组就可以 派上用场,就不会存进 stack 中相同的字符了。