题目:
Petya recieved a gift of a string s with length up to 105 characters for his birthday. He took two more empty strings t and u and decided to play a game. This game has two possible moves:
Extract the first character of s and append t with this character.
Extract the last character of t and append u with this character.
Petya wants to get strings s and t empty and string u lexicographically minimal.
You should write a program that will help Petya win the game.
输入
First line contains non-empty string s (1 ≤ |s| ≤ 105), consisting of lowercase English letters.
输出
Print resulting string u.
样例
输入
cab
输出
abc
输入
acdb
输出
abdc
题意:
给出了字符串s的内容,字符串t,u初始默认为空,允许做两种操作:
- 把s字符串第一个字符转移到t字符串最后。
- 把t字符串最后一个字符转移到u字符串最后。
最后要求s、t字符串都为空,问u字符串字典序最小能是多少。
题解:
本题实质为一个栈混洗,s为初始栈,t为中间栈,u为结果栈。
我们考虑这样的贪心策略:如果t栈为空,那么做s->t;
如果t栈不空:
对于t栈顶,如果s栈中不存在比它字典序更小的单词,就做t->u
否则做s->t
下面我来试着证明一下这个贪心的正确性
对于t栈栈顶元素x,如果已经比s栈中所有元素都小了,那么将x转入u栈一定是最优决策;
如果s栈中最小的元素和x相同,那么将x转入u栈不会让结果变得更糟(反之则有可能)
如果s栈中最小的元素小于x,应该把这个比较小的元素放到t栈中,所以做s->t
代码
#include<bits/stdc++.h>
using namespace std;
stack<char> s;
stack<char> t;
vector<char> ANS;
int ss[30],n;
char input[100000+10];
void action1(void)//s to t
{
char x=s.top();
ss[x-'a']--;
// if(s.empty())
// printf("mark1\n");
s.pop();
t.push(x);
}
void action2(void)//t to u
{
char x=t.top();
// if(t.empty())
// printf("mark2\n");
t.pop();
ANS.push_back(x);
}
bool action2_ok(void)//if there is no character in s that is smaller than t.top()
{
if(t.empty())
return false;//if t is empty,we could just do action1
char x=t.top();
bool flag=true;
for(int i=0;i<x-'a';i++)
{
if(ss[i]!=0)
flag=false;
}
return flag;
}
int main(void)
{
memset(ss,0,sizeof(ss));
scanf("%s",input);
n=strlen(input);
for(int i=n-1;i>=0;i--)
s.push(input[i]);
for(int i=0;i<n;i++)
ss[input[i]-'a']++;
while(!s.empty()||!t.empty())
{
if(action2_ok())
action2();
else
action1();
}
for(auto it:ANS)
printf("%c",it);
printf("\n");
return 0;
}