AI刷题题解(四)| 豆包MarsCode AI刷题

62 阅读4分钟

构造回文字符串问题之题解

题目概述

小C手中有一个由小写字母组成的字符串 s。她希望构造另一个字符串 t,并且这个字符串需要满足以下几个条件:

  1. t 由小写字母组成,且长度与 s 相同。
  2. t 是回文字符串,即从左到右与从右到左读取相同。
  3. t 的字典序要小于 s,并且在所有符合条件的字符串中字典序尽可能大。

小C想知道是否能构造出这样的字符串 t,输出这样的t。如果无法构造满足条件的字符串,则输出 -1

  • 测试样例
  • 样例1:

输入:s = "abc"
输出:'aba'

  • 样例2:

输入:s = "cba"
输出:'cac'

  • 样例3:

输入:s = "aaa"
输出:'-1'

解题思路

问题理解

按照题意,需要构造一个回文字符串 t,这个字符串的字典序要小于给定的字符串 s,并且在所有符合条件的字符串中字典序尽可能大。如果无法构造出满足条件的字符串,则返回 -1

考虑需要实现功能

  1. 回文特性:回文字符串的特点是正读和反读都相同。因此,可以将字符串 s 的前半部分作为 t 的前半部分,然后将其反转作为 t 的后半部分。
  2. 字典序比较:要确保 t 的字典序小于 s。为了实现这一点,可以从中间向两边逐步调整字符,使得 t 的字典序尽可能大但仍小于 s
  3. 特殊情况:如果 s 本身就是回文且无法找到更小的回文,则返回 -1

算法步骤

  1. 初始化字符数组:用一个字符数组 t 来存储构造的回文字符串。
  2. 复制前半部分:将 s 的前半部分复制到 t 的前半部分,并将其反转作为 t 的后半部分。
  3. 字典序比较:检查构造的 t 是否小于 s
  4. 调整字典序:如果 t 不小于 s,从中间向两边调整字符,使得 t 的字典序尽可能大但仍小于 s
  5. 返回结果:如果无法构造出满足条件的字符串,返回 -1

实现代码

public class Main {
    public static String solution(String s) {
        int n = s.length();
        //初始化一个与字符串 s 内字符排列顺序一样的字符数组t
        char[] t = s.toCharArray();
        
        //将 t 的前半部分复制到 t 的后半部分
        for (int i = 0; i < (n + 1) / 2; i++) {
            t[n - 1 - i] = t[i];
        }
        
        //检查 t 是否小于 s,并且是回文
        if (new String(t).compareTo(s) < 0) {
            return new String(t);
        }
        
        //如果 t 不小于 s,尝试调整 t 的字典序
        for (int i = (n - 1) / 2; i >= 0; i--) {
            if (t[i] > 'a') {
                t[i]--;
                t[n - 1 - i] = t[i];
                //从当前位置向两边扩展,尽可能使字典序最大
                for (int j = i + 1; j <= (n - 1) / 2; j++) {
                    t[j] = 'z';
                    t[n - 1 - j] = 'z';
                }
                return new String(t);
            }
        }
        
        //如果无法构造出满足条件的字符串,返回 -1
        return "-1";
    }

    public static void main(String[] args) {
        System.out.println(solution("cbcaacb").equals("cbbzbbc"));
        System.out.println(solution("abc").equals("aba"));
        System.out.println(solution("cba").equals("cac"));
        System.out.println(solution("aaa").equals("-1"));
    }
}

输出范例

true
true
true
true

具体运行步骤

  1. 初始化字符数组

    • 输入字符串 s = "cbcaacb"
    • 初始化字符数组 t,长度及元素与 s 相同,即 t = ['c', 'b', 'c', 'a', 'a', 'c', 'b']
  2. 复制前半部分

    • 将 s 的前半部分复制到 t 的前半部分,并将其反转作为 t 的后半部分。
    • 前半部分:s[0:3] = "cbc"
    • 后半部分:s[4:7] = "acb"
    • 复制后:t = ['c', 'b', 'c', 'a', 'c', 'b', 'c']
  3. 字典序比较

    • 检查 t 是否小于 s
    • t = "cbcabac"s = "cbcaacb"。1. - "cbcabac" 的字典序大于 "cbcaacb",因此需要进一步调整。
  4. 调整字典序

    • 从中间向两边调整字符,使得 t 的字典序尽可能大但仍小于 s
    • 从中间位置 (n-1)/2 = 3 开始调整。
    • t[3] = 'a't[3] > 'a' 不成立,继续向前调整。
    • t[2] = 'c't[2] > 'a' 成立,将 t[2] 减一,t[2] = 'b't[4] = 'b'
    • 从当前位置向两边扩展,尽可能使字典序最大。
    • t = ['c', 'b', 'b', 'a', 'b', 'b', 'c']
  5. 返回结果

    • 检查 t 是否小于 s
    • t = "cbbabbc"s = "cbcaacb""cbbabbc" 的字典序小于 "cbcaacb",返回 "cbbabbc"

用到的Java方法

  1. 初始化字符数组

    • 使用 s.toCharArray() 将字符串 s 转换为字符数组 t
  2. 复制前半部分

    • 使用 for 循环将 s 的前半部分复制到 t 的前半部分,并将其反转作为 t 的后半部分。
  3. 字典序比较

    • 使用 new String(t).compareTo(s) < 0 检查构造的 t 是否小于 s
  4. 调整字典序

    • 使用 for 循环从中间向两边调整字符,使得 t 的字典序尽可能大但仍小于 s
  5. 返回结果

    • 使用 return new String(t) 返回构造的回文字符串。如果无法构造出满足条件的字符串,返回 "-1"