链接:https://nanti.jisuanke.com/t/39614
题意:给你一个字符串和k,求字典序最小的长度为k的子序列。
贪心思路:开26个队列,将字母的位置放入队列中。贪心的往k个位置上放字母,即从‘a’到'z'尝试,首先尝试字母的位置要大于放的上一个字母的位置。如果尝试字母的位置后面的字母数加上已经放的字母数小于k,则不能放,否则就放。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 5e6+10;
char s[N],ans[N];
int k,len,now;
queue<int> q[30];
int main(void)
{
scanf("%s%d",s+1,&k);
len=strlen(s+1);
for(int i=1;i<=len;i++)
q[s[i]-'a'+1].push(i);
now=0;
for(int i=1;i<=k;i++)
{
for(int j=1;j<=26;j++)
{
while(!q[j].empty()&&q[j].front()<=now) q[j].pop();
if(!q[j].empty())
{
//cout<<(char)('a'+j-1)<<" "<<i+len-q[j].front()<<endl;
if(i+len-q[j].front()>=k)
{
ans[i]='a'+j-1;
now=q[j].front();
break;
}
}
}
}
ans[k+1]='\0';
printf("%s\n",ans+1);
return 0;
}
单调栈思路:维护一个单调递增的栈,并且要保证栈内的字母个数大于等于k,最后栈里的字母个数有可能大于k所以要取k个。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 5e6+10;
stack<char> st;
char s[N],ans[N];
int len,k,in;
int main(void)
{
in=0;
scanf("%s%d",s+1,&k);
len=strlen(s+1);
for(int i=1;i<=len;i++)
{
while(!st.empty()&&st.size()+len-i+1>k&&st.top()>s[i])
st.pop();
st.push(s[i]);
}
while(st.size()>k)
st.pop();
while(st.size())
{
ans[in++]=st.top();
st.pop();
}
for(int i=in-1;i>=0;i--)
printf("%c",ans[i]);
printf("\n");
return 0;
}