【力扣·每日一题】2182.构造限制重复的字符串(模拟 贪心 优先队列 C++ Go)

题目链接

题意

给你一个字符串 s 和一个整数 repeatLimit ,用 s 中的字符构造一个新字符串 repeatLimitedString ,使任何字母 连续 出现的次数都不超过 repeatLimit 次。你不必使用 s 中的全部字符。

返回 字典序最大的 repeatLimitedString 。

如果在字符串 a 和 b 不同的第一个位置,字符串 a 中的字母在字母表中出现时间比字符串 b 对应的字母晚,则认为字符串 a 比字符串 b 字典序更大 。如果字符串中前 min(a.length, b.length) 个字符都相同,那么较长的字符串字典序更大。

提示:

1 < = r e p e a t L i m i t < = s . l e n g t h < = 1 0 5 1 <= repeatLimit <= s.length <= 10^5 1<=repeatLimit<=s.length<=105

s 由小写英文字母组成

思路

贪心的构造

  • 每次将当前剩余的字典序最大的字符添加到答案里,如果该字符已经连续出现了repeatLimit 次,则先将当前剩余的字典序次大的字符添加到答案里,再继续将当前剩余的字典序最大的字符添加到答案里,直到该最大的字符用完或是没有次大的字符可以插入

有两种写法

  1. 多层for循环,不断尝试填入新字符
    • 结合上述的思路可以得知,每个字符i最多被添加min(repeatLimit,mp[i])次,其中mp[i]为字符i的出现次数
    • 可以先统计字符串s里每个字符的出现次数
    • 倒序进行遍历,这时候i里维护的就是当前剩余的字典序最大的字符
    • 尝试将字符i添加到答案字符串里
    • 如果i已经填完了的话,跳出循环,找下一个当前剩余的字典序最大的字符
    • 否则的话找第一个存在且字典序次大的字符 ,插入到答案字符串里,这样后面就可以继续填字母i
  2. 使用优先队列维护字典序最大字符和次大字符
    • 思路1的本质是通过for循环找当前剩余的字典序最大/次大的字符,可以通过优先队列来维护

代码

go 复制代码
func repeatLimitedString(s string, repeatLimit int) string {
	mp := make(map[rune]int, 26)
	for _, ch := range s {
		mp[ch]++
	}
	ans := make([]rune,0,len(s))
	for i := 'z'; i >= 'a'; i-- {//倒序填入字母
		las := i - 1//记录次小的字母值
		for {
			for j := 0; j < repeatLimit && mp[i] > 0; j++ {//最多填入min(repeatLimit,mp[i])个字母i
				mp[i]--
				ans = append(ans, i)
			}
			if mp[i] == 0 {//i填完了 找下一个字典序最大的字母
				break
			}
			for las >= 0 && mp[las] == 0 {//找到第一个存在的字典序次大的字母
				las--
			}
			if las < 0 {//找不到 跳出
				break
			}
            //先填入次大字母 后面可以继续填最大字母i
			mp[las]--
			ans = append(ans, las)
		}
	}
	return string(ans)
}
cpp 复制代码
class Solution {
	public:
		string repeatLimitedString(string s, int repeatLimit) {
			int mp[26];
			for(int i=0; i<26; i++) {
				mp[i]=0;
			}
			for(char ch:s) {
				mp[ch-'a']++;
			}
			string ans;
			for(int i=25; i>=0; i--) {
				int las = i-1;
				while(1) {
					for(int j=0; j<repeatLimit&&mp[i]>0; j++) {
						mp[i]--;
                        ans.push_back(i+'a');
                    	//ans = ans + char(i+'a');
					}
					if(mp[i]==0) {
						break;
					}
					while(las>=0&&mp[las]==0) {
						las--;
					}
					if(las < 0) {
						break;
					}
					mp[las]--;
                    ans.push_back(las+'a');
                //	ans = ans + char(las+'a');
				}
			}
			return ans;
		}
};
相关推荐
Once_day5 分钟前
C++之《程序员自我修养》读书总结(1)
c语言·开发语言·c++·程序员自我修养
Trouvaille ~15 分钟前
【Linux】TCP Socket编程实战(一):API详解与单连接Echo Server
linux·运维·服务器·网络·c++·tcp/ip·socket
偷吃的耗子21 分钟前
【CNN算法理解】:CNN平移不变性详解:数学原理与实例
人工智能·算法·cnn
坚果派·白晓明27 分钟前
在鸿蒙设备上快速验证由lycium工具快速交叉编译的C/C++三方库
c语言·c++·harmonyos·鸿蒙·编程语言·openharmony·三方库
小镇敲码人34 分钟前
深入剖析华为CANN框架下的Ops-CV仓库:从入门到实战指南
c++·python·华为·cann
dazzle1 小时前
机器学习算法原理与实践-入门(三):使用数学方法实现KNN
人工智能·算法·机器学习
那个村的李富贵1 小时前
智能炼金术:CANN加速的新材料AI设计系统
人工智能·算法·aigc·cann
张张努力变强2 小时前
C++ STL string 类:常用接口 + auto + 范围 for全攻略,字符串操作效率拉满
开发语言·数据结构·c++·算法·stl
万岳科技系统开发2 小时前
食堂采购系统源码库存扣减算法与并发控制实现详解
java·前端·数据库·算法
小镇敲码人2 小时前
探索CANN框架中TBE仓库:张量加速引擎的优化之道
c++·华为·acl·cann·ops-nn