142. 字典序最小回文构造问题 解析 | 豆包MarsCode AI刷题

53 阅读3分钟

题目大意

给定一个由小写英文字母组成的字符串,最多可以更改字符串中的两个字符,构造出字典序最小的回文字符串。

测试样例及解释

样例1:

输入:s = "acca"
输出:'aaaa'

原字符串已经回文,因此可以修改二三两位的字符使其字典序更小。

样例2:

输入:s = "racecar"
输出:'aacecaa'

为了使字典序最小,第一位一定是最优先被修改的;为了保证回文,最后一位也需要被修改。

样例3:

输入:s = "fecdef"
输出:'feccef'

原字符串并不回文,因此需要修改第三位或第四位;为了使字典序最小,可以选择修改第四位。修改后只剩下一次修改次数,无法继续进行修改。

解题思路

  1. 找到不匹配的位置

    • 通过遍历字符串的前半部分,找到前两个不匹配的位置。
  2. 修改不匹配的字符

    • 将不匹配的字符修改为字典序较小的字符,确保回文性。
  3. 尽量将字符改为 'a'

    • 如果还有修改次数,尽量将字符改为 'a',以确保字典序最小。
  4. 处理奇数长度字符串

    • 如果字符串长度为奇数且还有一次修改机会,修改中间字符为 '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",就能节约我们一次修改的次数。其余的部分就没有什么区别了。

不过我在修正的这个错误之后再次提交反而告诉我答案错了,看来是出数据的人犯了同样的错误。目前已经反馈了,不知道什么时候可以改正这个问题。