2019 计蒜之道 复赛 D——“星云系统”(单调栈||队列+贪心)

探讨了如何求解字符串的字典序最小长度为k的子序列问题,提供了两种解决方案:单调栈模拟和队列加贪心算法,并附带详细代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  •  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;
} 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

心脏dance

如果解决了您的疑惑,谢谢打赏呦

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值