- 19.97%
- 1000ms
- 131072K
VIPKID 是在线少儿英语教育平台,网络稳定是在线教育课程质量的红线,VIPKID 为此推出了全球最稳定的教育网络系统 —— “星云系统”。星云系统目前建立了覆盖全球 3535 个国家的 55 条核心跨海专线,在 1616 个国家的 5555 个城市建立了中心传输节点,具备一分钟内自由切换路由的能力,确保了全球跨洋课堂的高清音、视频通信,为流畅的课堂体验打下坚实基础。
全世界的中心传输节点和各地的网络节点组成的这个“星云系统”,何其复杂。我们现在只考虑一条支线上的网络节点,每一个网络节点比作一个字符的话,这条支线就是一个字符串。
现在给定你一个字符串 ss 以及一个整数 kk,请求出 ss 的字典序最小的长度为 kk 的子序列。
输入格式
第一行一个由小写英文字母构成的字符串 ss,第二行一个正整数 kk。
输出格式
一行一个字符串 ans
,表示答案。
数据规模
0 < k \leq |s| \leq50000000<k≤∣s∣≤5000000
样例输入复制
helloworld
5
样例输出复制
ellld
题意:给定你一个字符串 s 以及一个整数 k,请求出 s 的字典序最小的长度为 k 的子序列。
题解:两种方法,单调栈模拟或者队列+贪心
1. 单调栈模拟,保证栈内至少有k个元素,如果要进栈的元素<栈顶元素,就把栈顶元素弹出来,模拟即可,最后输出前k个,因为栈内可能多于k个~~
比如样例:abcd 2 这样的话代码跑完栈内就有abcd,只需要输出前两个~~~
上代码:
#include <iostream>
#include <stack>
#include <algorithm>
using namespace std;
stack<char> st;
int main(){
string s;
cin >> s;
int k;
cin >> k;
int len=s.size();
for (int i = 0; i < len;i++){
int w=max(k-len+i,0);//保证栈内至少有k个元素
while(st.size()>w&&s[i]<st.top()) st.pop();//如果要进栈的元素<栈顶元素,就把栈顶元素弹出来
st.push(s[i]);
}
string ss="";
while(!st.empty()){
ss+=st.top();
st.pop();
}
reverse(ss.begin(),ss.end());
cout << ss.substr(0,k) << endl;//输出前k个,栈内可能多于k个
return 0;
}
2. 队列加贪心,把26个字母的位置对应放到26个队列中,然后尝试放在k个位置上,每次循环放一个,放的那一个就是贪心最优的(位置必须大于上一个放的),当然想要放上最优的,要看该位置后面,和已经放上的加起来是不是还能到达k个字母~~
上代码:
#include <iostream>
#include <cstdio>
#include <queue>
using namespace std;
queue<int> q[30];
int main(){
string s;
cin >> s;
int k;
cin >> k;
int len=s.size();
for (int i = 0; i < s.size();i++){
q[s[i]-'a'].push(i+1);
}
int now=0;
string ss="";
for (int i = 1; i <= k;i++){
for (int j = 0; j < 26;j++){
while(!q[j].empty()&&now>=q[j].front()) q[j].pop();//找大于上一个的位置的
if(!q[j].empty()&&i+(len-q[j].front())>=k){//判断是不是还能够k个
ss+=('a'+j);
now=q[j].front();
break;
}
}
}
cout << ss << endl;
return 0;
}