学习笔记:回文字符串构造与字典序优化
一、题目概述
小C手中有一个由小写字母组成的字符串 ss,她需要构造一个回文字符串 tt,满足以下条件:
- tt 是回文字符串,即从左到右与从右到左相同。
- tt 的字典序要小于 ss,并且在所有符合条件的字符串中,字典序尽可能大。
- 如果无法构造出符合条件的回文字符串,返回
-1。
二、解题思路
1. 回文字符串的构造:
回文字符串的特点是其前半部分决定了后半部分。也就是说,如果我们确定了前半部分的字符,后半部分就可以直接对称得到。
- 例如,如果 s="abc"s = "abc",我们可以尝试构造回文字符串
"aba",将字符串前半部分的字符反转并作为后半部分。
2. 字典序要求:
- 我们希望 tt 的字典序尽可能大,但必须小于原字符串 ss。
- 由于回文字符串的特性,我们只需要调整前半部分的字符来满足字典序条件。通过从后向前调整字符,使其字典序尽可能大但又小于 ss。
3. 解题步骤:
-
初步构造回文字符串:
- 根据 ss 的前半部分构造一个回文字符串 tt,将其后半部分与前半部分对称。
-
检查字典序:
- 如果初步构造的回文字符串 tt 已经小于 ss,直接返回它。
-
调整前半部分:
- 如果初步构造的回文字符串 tt 不满足字典序小于 ss,则从后向前调整前半部分的字符。每次将字符减小并重新构造回文字符串,直到找到符合条件的结果。
-
边界条件:
- 如果无法调整字符(即所有字符已经是最小的字典序),返回
-1。
- 如果无法调整字符(即所有字符已经是最小的字典序),返回
三、代码实现
#include <iostream>
#include <string>
std::string make_palindrome_less_than(std::string s) {
int n = s.size();
std::string t = s;
// Step 1: Construct an initial palindrome by copying the first half of s
for (int i = 0; i < n / 2; ++i) {
t[n - i - 1] = s[i];
}
// Step 2: Check if this palindrome is already less than s
if (t < s) {
return t;
}
// Step 3: Try to adjust the first half of the string to get the largest possible palindrome less than s
for (int i = n / 2 - 1; i >= 0; --i) {
if (t[i] > 'a') {
// Decrease the character at position i
t[i]--;
// Rebuild the palindrome
for (int j = i + 1; j < n / 2; ++j) {
t[j] = 'z'; // Maximize the characters on the right part of the palindrome
}
for (int j = 0; j <= i; ++j) {
t[n - j - 1] = t[j]; // Mirror the changes on the second half
}
return t;
}
}
// Step 4: If no valid palindrome is found
return "-1";
}
int main() {
std::string s;
std::cin >> s;
std::string result = make_palindrome_less_than(s);
std::cout << result << std::endl;
return 0;
}
代码解析:
-
初步构造回文字符串:
- 根据 ss 的前半部分构造回文字符串 tt。
- 如果 tt 已经小于 ss,直接返回 tt。
-
调整回文字符串:
- 从回文字符串的后半部分开始,逐步减少前半部分的字符,并重新构造回文字符串,确保字典序尽可能大但小于 ss。
-
返回结果:
- 如果找到符合条件的回文字符串,则返回它;如果无法找到,则返回
-1。
- 如果找到符合条件的回文字符串,则返回它;如果无法找到,则返回
四、复杂度分析
时间复杂度:
- 构造回文字符串的时间复杂度是 O(n)O(n),其中 nn 是字符串的长度。
- 调整前半部分的字符时,最坏的情况下我们需要对每个字符进行调整,时间复杂度仍为 O(n)O(n)。
因此,整体时间复杂度为 O(n)O(n) 。
空间复杂度:
- 我们仅使用了一个额外的字符串 tt 来存储回文字符串,因此空间复杂度为 O(n)O(n) 。
五、测试样例分析
样例1:
输入:s = "abc"
输出:"aba"
- 初步构造回文字符串为
"aba",其字典序小于"abc",符合条件。
样例2:
输入:s = "cba"
输出:"cac"
- 初步构造回文字符串为
"cbc",字典序不小于"cba"。调整前半部分字符得到"cac",符合条件。
样例3:
输入:s = "aaa"
输出:"-1"
- 无法构造出符合条件的回文字符串,因为所有字符都是 'a',已经是字典序最小。
六、学习心得
1. 回文字符串的特性:
- 通过利用回文字符串的对称性,我们能够减少问题的复杂度,避免暴力枚举所有可能的回文字符串。
2. 字典序优化:
- 通过从后向前调整字符,确保每次修改都能使得字符串尽可能大,同时不违反字典序小于原字符串的约束。
3. 编程技巧:
- 在字符串问题中,学会合理地利用字符操作和对称性优化算法,能大幅提高效率。
七、总结
本题考察了如何在回文字符串中进行优化,确保生成的字符串字典序尽可能大同时又满足小于原字符串的约束。通过对回文字符串的结构理解,能够有效地解决问题,并通过调整字符的方式获得最佳解。