构造回文字符串问题之题解
题目概述
小C手中有一个由小写字母组成的字符串 s。她希望构造另一个字符串 t,并且这个字符串需要满足以下几个条件:
t由小写字母组成,且长度与s相同。t是回文字符串,即从左到右与从右到左读取相同。t的字典序要小于s,并且在所有符合条件的字符串中字典序尽可能大。
小C想知道是否能构造出这样的字符串 t,输出这样的t。如果无法构造满足条件的字符串,则输出 -1。
- 测试样例
- 样例1:
输入:
s = "abc"
输出:'aba'
- 样例2:
输入:
s = "cba"
输出:'cac'
- 样例3:
输入:
s = "aaa"
输出:'-1'
解题思路
问题理解
按照题意,需要构造一个回文字符串 t,这个字符串的字典序要小于给定的字符串 s,并且在所有符合条件的字符串中字典序尽可能大。如果无法构造出满足条件的字符串,则返回 -1。
考虑需要实现功能
- 回文特性:回文字符串的特点是正读和反读都相同。因此,可以将字符串
s的前半部分作为t的前半部分,然后将其反转作为t的后半部分。 - 字典序比较:要确保
t的字典序小于s。为了实现这一点,可以从中间向两边逐步调整字符,使得t的字典序尽可能大但仍小于s。 - 特殊情况:如果
s本身就是回文且无法找到更小的回文,则返回-1。
算法步骤
- 初始化字符数组:用一个字符数组
t来存储构造的回文字符串。 - 复制前半部分:将
s的前半部分复制到t的前半部分,并将其反转作为t的后半部分。 - 字典序比较:检查构造的
t是否小于s。 - 调整字典序:如果
t不小于s,从中间向两边调整字符,使得t的字典序尽可能大但仍小于s。 - 返回结果:如果无法构造出满足条件的字符串,返回
-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
具体运行步骤
-
初始化字符数组:
- 输入字符串
s = "cbcaacb"。 - 初始化字符数组
t,长度及元素与s相同,即t = ['c', 'b', 'c', 'a', 'a', 'c', 'b']。
- 输入字符串
-
复制前半部分:
- 将
s的前半部分复制到t的前半部分,并将其反转作为t的后半部分。 - 前半部分:
s[0:3] = "cbc"。 - 后半部分:
s[4:7] = "acb"。 - 复制后:
t = ['c', 'b', 'c', 'a', 'c', 'b', 'c']。
- 将
-
字典序比较:
- 检查
t是否小于s。 t = "cbcabac",s = "cbcaacb"。1. -"cbcabac"的字典序大于"cbcaacb",因此需要进一步调整。
- 检查
-
调整字典序:
- 从中间向两边调整字符,使得
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']。
- 从中间向两边调整字符,使得
-
返回结果:
- 检查
t是否小于s。 t = "cbbabbc",s = "cbcaacb"。"cbbabbc"的字典序小于"cbcaacb",返回"cbbabbc"。
- 检查
用到的Java方法
-
初始化字符数组:
- 使用
s.toCharArray()将字符串s转换为字符数组t。
- 使用
-
复制前半部分:
- 使用
for循环将s的前半部分复制到t的前半部分,并将其反转作为t的后半部分。
- 使用
-
字典序比较:
- 使用
new String(t).compareTo(s) < 0检查构造的t是否小于s。
- 使用
-
调整字典序:
- 使用
for循环从中间向两边调整字符,使得t的字典序尽可能大但仍小于s。
- 使用
-
返回结果:
- 使用
return new String(t)返回构造的回文字符串。如果无法构造出满足条件的字符串,返回"-1"。
- 使用