【贪心 字典序 回文 最长公共前缀】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++**实现。

相关推荐
weixin_514221853 小时前
FDTD代码学习-1
学习·算法·lumerical·fdtd
AI柠檬3 小时前
机器学习:数据集的划分
人工智能·算法·机器学习
_OP_CHEN3 小时前
C++进阶:(四)set系列容器的全面指南
开发语言·c++·stl·set·multiset·关联式容器·setoj题
让我们一起加油好吗4 小时前
【数论】裴蜀定理与扩展欧几里得算法 (exgcd)
算法·数论·裴蜀定理·扩展欧几里得算法·逆元
Geo_V4 小时前
提示词工程
人工智能·python·算法·ai
侯小啾4 小时前
【22】C语言 - 二维数组详解
c语言·数据结构·算法
qq_479875434 小时前
Linux time function in C/C++【2】
linux·c语言·c++
TL滕4 小时前
从0开始学算法——第一天(如何高效学习算法)
数据结构·笔记·学习·算法
傻童:CPU4 小时前
DFS迷宫问题
算法·深度优先