构造回文字符串问题 | 2024 刷题 掘金 MarsCode 中等题

130 阅读3分钟

问题描述

小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'

问题分析

题目要求在满足条件的情况下,尽可能的使字符串的字典序最大,这满足贪心算法的策略。根据题目的要求,需要字典序最大,量度指标为每次保证字符串前面的字符尽可能大。分析题目条件:

  1. t的字典序要小于s,这表明t从左到右的每个字符不能超过s对应的位置的字符。
  2. t是回文字符串,即从左到右和从右到左的读取相同。
  3. t的长度与s相同,因此比较t和s字符串是最需要一一比较相同索引的字符。

由此,我们考虑一下步骤:

  1. 首先构建一个初始的回文字符串t,由于t不能大于s,因此遍历s前面一半的字符串,s[i] = s[length-1]构建回文字符串。
  2. 构建的t有三种情况:(1)如果t小于s,那么直接满足条件。(2)如果s所有字符都为'a',t无法小于s,则输出为-1。(3)如果t大于或者等于s。那么需要将满足条件的最小位置的字符-1,保存其他位置字符尽可能大,这样导致的损失最小。
  3. 最小位置应该是中间位置,即t[length/2],但是如果t[length/2] = 'a',无法减小,那么需要向前考虑一位,直到t[index] > 'a' 则,t[index] = t[index] - 1。对应的t[length - 1-index] = t[index]修改。修改后无论index后面的字符多大,t都小于s,则将t[index+1] 到 t[length - index]直接的所有字符修改成最大值'z'。

完整代码如下

public class Main {
    public static String solution(String s) {
        // write code here
        int length = s.length();
        char[] str = s.toCharArray();
        char[] tmp = new char[length];

        int flag = 0; // str和tmp相同
        for(int i=0; i<length/2; i++){
            tmp[i] = str[i];
            tmp[length-i-1] = str[i];
            if(tmp[length-1-i] >  str[length-1-i])
                flag = 1; // str 小于 tmp
            else if(tmp[length-1-i] <  str[length-1-i])
                flag = 2; // str 大于 tmp
        }

        // 考虑长度为奇数和偶数的情况。
        if(length%2 == 1)
            tmp[length/2] = str[length/2]; // 奇数长度的字符串,tmp[length/2] = str[length/2]
        if(flag == 0 || flag == 1){
            int index = length/2;
            while(index < length){
                if(tmp[index] != 'a'){ // 找到能够使t小于s的最小索引位置。
                    tmp[index] = (char)(tmp[index] - 1);
                    tmp[length - 1 - index] = tmp[index];
                    break;
                }
                index++;
            }
            if(index == length)
                return "-1";
            index--;
            while(index >= length/2){ // 返回来将中间字符取最高值。
                tmp[index] = 'z';
                tmp[length - 1 - index] = tmp[index];
                index--;
            }
        }
        String result = "";
        for(char c : tmp){
            result += c;
        }
//        System.out.println(result);
        return result;
    }

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

问题总结

这题主要考察问题分析能力,涵盖字符串回文特性、贪心算法、边界条件处理的知识点,在编写代码时,需要注意细节问题,例如奇数长度和偶数长度中间值的索引如何表示,如果仔细可能会存在错误。

(个人总结,有问题请指出)