【贪心 字典序 回文 最长公共前缀】LeetCode3734. 大于目标字符串的最小字典序回文排列|分数未知

本文涉及知识点

C++贪心

LeetCode3734. 大于目标字符串的最小字典序回文排列

返回 字典序最小的字符串 ,该字符串 既 是 s 的一个 回文排列 ,又是字典序 严格 大于 target 的。如果不存在这样的排列,则返回一个空字符串。

如果字符串 a 和字符串 b 长度相同,在它们首次出现不同的位置上,字符串 a 处的字母在字母表中的顺序晚于字符串 b 处的对应字母,则字符串 a 在 字典序上严格大于 字符串 b。

排列 是指对字符串中所有字符的重新排列。

如果一个字符串从前向后读和从后向前读都一样,则该字符串是 回文 的。

示例 1:

输入: s = "baba", target = "abba"

输出: "baab"

解释:

复制代码
s 的回文排列(按字典序)是 "abba" 和 "baab"。
字典序最小的、且严格大于 target 的排列是 "baab"。

示例 2:

输入: s = "baba", target = "bbaa"

输出: ""

解释:

复制代码
s 的回文排列(按字典序)是 "abba" 和 "baab"。
它们中没有一个在字典序上严格大于 target。因此,答案是 ""。

示例 3:

输入: s = "abc", target = "abb"

输出: ""

解释:

s 没有回文排列。因此,答案是 ""。

示例 4:

输入: s = "aac", target = "abb"

Output: "aca"

解释:

复制代码
s 唯一的回文排列是 "aca"。
"aca" 在字典序上严格大于 target。因此,答案是 "aca"。

提示:

复制代码
1 <= n == s.length == target.length <= 300
s 和 target 仅由小写英文字母组成。

贪心 字典序 回文 最长公共前缀

N = s.lenght N2 = N ÷ 2 N \div 2 N÷2

令ans是回文,且大于target。

n = ans和target的最长公共前缀长度。
性质一 :cnt[i]记录'a'+i在s中的数量。 ( ∑ i : 0 26 c n t [ i ] 是奇数 ) ≤ 1    ⟺    s 是否存在排列是回文 (\sum_{i:0}^{26}cnt[i]是奇数) \le 1 \iff s是否存在排列是回文 (∑i:026cnt[i]是奇数)≤1⟺s是否存在排列是回文 。只需要求ans[ 0 ∼ N 2 − 1 ] 0 \sim N2-1] 0∼N2−1],后半部分对称。如果N是奇数,则ans[N2] = 唯一的奇数字符。
性质二 :n越大,则字典序越小。
性质三 : n ≥ N 2 n \ge N2 n≥N2,由于回文串,则ans都相等,故只需要枚举 n = = N 2 n==N2 n==N2,无序枚举n > N2。
性质四: n<N2,n相同,ans[n]>target[n],且最小。

实现

由于ans[ 0 ∼ N 2 − 1 0 \sim N2-1 0∼N2−1]使用cnt[i]/2个字符。可cnt[i]/=2。
时间复杂度:O(N)

代码

核心代码

cpp 复制代码
class Solution {
		public:
			string lexPalindromicPermutation(string s, string target) {
				this->s = s;this->t = target;
				N = s.length();
				int cnt[26] = { 0 };
				for (const auto& ch : s) { cnt[ch - 'a']++; }
				int evenIndex = -1;
				for (int i = 0;i < 26;i++) {
					if (cnt[i] & 1) {
						if (-1 != evenIndex) { return ""; }
						evenIndex = i;
					}
				}
				for (int i = 0;i < 26;i++) {
					cnt[i] /= 2;
				}
				//最长公共前缀为[0,N/2]
				int maxn = -1, next = -1;
				int n = 0;
				for (;n < N / 2;n++)
				{
					const int cur = target[n] - 'a';
					for (int j = cur+1;j < 26;j++)
					{
						if (cnt[j]) {
							maxn = n;next = j;
							break;
						}
					}
					if (cnt[cur] <=0) { break; }
					cnt[cur]--;
				}
				if (N / 2 == n) {
					string ans = DoHalfAns(target.substr(0, N / 2), evenIndex);
					if (ans > target) { return ans; }
				}
				if (-1 == maxn) { return ""; }
				string ans = Do(maxn, next);
				return DoHalfAns(ans, evenIndex);
			}
			string DoHalfAns(string half,int evenIndex) {	
				if (N & 1) {
					half += 'a' + evenIndex;
				}
				for (int i = N / 2 - 1;i >= 0;i--) {
					half += half[i];
				}
				return half;
			}
			string Do(int maxn, int next) {
				int cnt[26] = { 0 }, sel[26] = { 0 };
				for (const auto& ch : s) { cnt[ch - 'a']++; }
				int i = 0;
				string ans;
				for (;i < maxn;i++) {
					ans += t[i];
					sel[t[i] - 'a']++;
				}
				ans += 'a' + next;
				i++;
				sel[next]++;				
				for (int j = 0;i < N / 2;i++) {
					while (sel[j] >= cnt[j] / 2) { j++;	}
					ans += 'a' + j;
					sel[j]++;
				}
				return ans;
			}
			vector<string> m_ans;
			string s, t;
			int N;
		};

单元测试

cpp 复制代码
string s, target;

		TEST_METHOD(TestMethod11)
		{	
			s = "baba", target = "abba";
			auto res = Solution().lexPalindromicPermutation(s, target);
			AssertEx(string("baab"), res);
		}
		TEST_METHOD(TestMethod12)
		{
			s = "baba", target = "bbaa";
			auto res = Solution().lexPalindromicPermutation(s, target);
			AssertEx(string(""), res);
		}
		TEST_METHOD(TestMethod13)
		{
			s = "abc", target = "abb";
			auto res = Solution().lexPalindromicPermutation(s, target);
			AssertEx(string(""), res);
		}
		TEST_METHOD(TestMethod14)
		{
			s = "aac", target = "abb";
			auto res = Solution().lexPalindromicPermutation(s, target);
			AssertEx(string("aca"), res);
		}
		TEST_METHOD(TestMethod15)
		{
			s = "z", target = "a";
			auto res = Solution().lexPalindromicPermutation(s, target);
			AssertEx(string("z"), res);
		}
		TEST_METHOD(TestMethod16)
		{
			s = "abb", target = "aaa";
			auto res = Solution().lexPalindromicPermutation(s, target);
			AssertEx(string("bab"), res);
		}
		TEST_METHOD(TestMethod17)
		{
			s = "aabb", target = "abaa";
			auto res = Solution().lexPalindromicPermutation(s, target);
			AssertEx(string("abba"), res);
		}
		TEST_METHOD(TestMethod18)
		{
			s = "aabb", target = "baab";
			auto res = Solution().lexPalindromicPermutation(s, target);
			AssertEx(string(""), res);
		}

总结

由于n比较小,故可以用时间复杂度O(NN),甚至O(NNN)的算法。

扩展阅读

我想对大家说的话
工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。
学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注
员工说:技术至上,老板不信;投资人的代表说:技术至上,老板会信。
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛
失败+反思=成功 成功+反思=成功

视频课程

先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

测试环境

操作系统:win7 开发环境: VS2019 C++17

或者 操作系统:win10 开发环境: VS2022 C++17

如无特殊说明,本算法 用**C++**实现。

相关推荐
八月的雨季 最後的冰吻1 天前
FFmepg-- 41-ffplay源码- -快进快退seek
c++·算法·音视频
Swift社区1 天前
LeetCode 466 统计重复个数
算法·leetcode·职场和发展
橘颂TA1 天前
【剑斩OFFER】算法的暴力美学——字母异位词分组
数据结构·算法·leetcode·力扣·哈希算法·散列表·结构与算法
苏宸啊1 天前
C++(一)入门
开发语言·c++
一把小椅子1 天前
超大规模多模态交通数据集:320TB+海量数据资源,涵盖行车视频、无人机航拍、第一视角步行骑行与道路监控,助力自动驾驶与智慧交通算法突破
算法·自动驾驶·无人机
闻缺陷则喜何志丹1 天前
【二分查找 图论】P10206 [JOI 2024 Final] 建设工程 2|普及+
c++·算法·二分查找·图论·洛谷
数据分享者1 天前
原创大规模无人机检测数据集:11998张高质量图像,支持YOLOv8、COCO、TensorFlow多格式训练,涵盖飞机、无人机、直升机三大目标类别
算法·yolo·数据分析·tensorflow·无人机
Sunsets_Red1 天前
对于吉司机线段树下传懒标记的顺序的解释
c语言·数据结构·数据库·c++·算法·c#·学习方法
C雨后彩虹1 天前
几何平均值最大子数组
java·数据结构·算法·华为·面试
想进个大厂1 天前
代码随想录day2 滑动窗口
java·数据结构·算法