本文涉及知识点
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++**实现。
