题目大意
给定一个由小写英文字母组成的字符串,最多可以更改字符串中的两个字符,构造出字典序最小的回文字符串。
测试样例及解释
样例1:
输入:
s = "acca"
输出:'aaaa'
原字符串已经回文,因此可以修改二三两位的字符使其字典序更小。
样例2:
输入:
s = "racecar"
输出:'aacecaa'
为了使字典序最小,第一位一定是最优先被修改的;为了保证回文,最后一位也需要被修改。
样例3:
输入:
s = "fecdef"
输出:'feccef'
原字符串并不回文,因此需要修改第三位或第四位;为了使字典序最小,可以选择修改第四位。修改后只剩下一次修改次数,无法继续进行修改。
解题思路
-
找到不匹配的位置:
- 通过遍历字符串的前半部分,找到前两个不匹配的位置。
-
修改不匹配的字符:
- 将不匹配的字符修改为字典序较小的字符,确保回文性。
-
尽量将字符改为 'a':
- 如果还有修改次数,尽量将字符改为 'a',以确保字典序最小。
-
处理奇数长度字符串:
- 如果字符串长度为奇数且还有一次修改机会,修改中间字符为 'a'。
std::string solution(const std::string& s) {
int n = s.size();
int first_mismatch = -1, second_mismatch = -1;
// 找到前两个不匹配的位置
for (int i = 0; i < n / 2; i++) {
if (s[i] != s[n - i - 1]) {
if (first_mismatch == -1) {
first_mismatch = i;
} else if (second_mismatch == -1) {
second_mismatch = i;
}
}
}
std::string t = s;
int changes_left = 2;
// 修改第一个不匹配的位置
if (first_mismatch != -1) {
char min_char = std::min(t[first_mismatch], t[n - first_mismatch - 1]);
t[first_mismatch] = t[n - first_mismatch - 1] = min_char;
changes_left--;
}
// 修改第二个不匹配的位置
if (second_mismatch != -1) {
char min_char = std::min(t[second_mismatch], t[n - second_mismatch - 1]);
t[second_mismatch] = t[n - second_mismatch - 1] = min_char;
changes_left--;
}
// 如果还有修改次数,尽量将字符改为 'a'
for (int i = 0; i < n / 2 && changes_left > 0; i++) {
if (t[i] != 'a') {
t[i] = t[n - i - 1] = 'a';
changes_left -= 2;
}
}
// 如果字符串长度为奇数且还有一次修改机会,修改中间字符为 'a'
if (changes_left >= 1 && n % 2 == 1) {
t[n / 2] = 'a';
}
return t;
}
没错,以上解题思路是 MarsCode AI 根据我通过的代码给出的代码分析,讲的也算比较清晰,还顺便帮我把命名不怎么规范(偷懒)的变量名改成了更加容易看懂的名字。但我在写这篇题解时意外发现这种解法其实仍然存在问题,例如 "nw" 通过修改两个字符可以变成 "aa" ,而这个代码输出的却是 "nn"。
究其原因是我优先考虑将原字符串修改为回文,之后再单独考虑是否可以同时将一个对称的位置修改为 "a",因此可能存在这两者修改的是相同的位置,那就明显不需要两次修改浪费次数了。因此我们应该先记录下我们将要修改的那个对称的位置,然后再去判断这个位置是否不匹配,如果不匹配就可以直接将这两个位置同时修改为 "a",就能节约我们一次修改的次数。其余的部分就没有什么区别了。
不过我在修正的这个错误之后再次提交反而告诉我答案错了,看来是出数据的人犯了同样的错误。目前已经反馈了,不知道什么时候可以改正这个问题。