学习笔记:构造字典序最大且小于原字符串的回文字符串
问题背景
小C手中有一个由小写字母组成的字符串 s。她希望构造另一个字符串 t,并且这个字符串需要满足以下几个条件:
t由小写字母组成,且长度与s相同。t是回文字符串,即从左到右与从右到左读取相同。t的字典序要小于s,并且在所有符合条件的字符串中字典序尽可能大。
如果无法构造满足条件的字符串 t,则输出 -1。
问题分析
- 回文字符串的特性:回文字符串的特点是从中间向两边对称。因此,我们可以将字符串分为两部分:前半部分和后半部分(如果有奇数个字符,中间的字符单独处理)。
- 字典序的要求:构造的字符串
t必须小于原字符串s,并且在所有满足条件的字符串中字典序尽可能大。 - 构造方法:
- 先构造前半部分,使其尽可能接近
s的前半部分。 - 然后根据前半部分构造后半部分,使其成为回文字符串。
- 如果中间有字符,单独处理,使其尽可能大但仍小于
s的对应字符。
- 先构造前半部分,使其尽可能接近
解决方案
-
初始化:
- 获取字符串
s的长度n。 - 计算中间字符
mid(如果n是奇数)。 - 获取前半部分
half。
- 获取字符串
-
处理中间字符:
- 如果
mid不为空且大于'a',尝试将其减1,构造回文字符串并检查是否小于s。 - 如果
mid为空或等于'a',将其设为'z'。
- 如果
-
处理前半部分:
- 从右半部分的末尾开始向前遍历,尝试将每个字符减1,构造回文字符串并检查是否小于
s。 - 如果找到一个合适的字符,构造回文字符串并返回。
- 如果所有字符都已处理完毕且无法构造满足条件的字符串,返回
-1。
- 从右半部分的末尾开始向前遍历,尝试将每个字符减1,构造回文字符串并检查是否小于
代码实现
def solution(s: str) -> str:
n = len(s)
mid = s[n // 2] if n % 2 != 0 else ''
half = s[:n // 2]
# 处理中间字符
if mid > "a":
new_mid = chr(ord(mid) - 1)
candidate = half + new_mid + half[::-1]
if candidate < s:
return candidate
return half + new_mid + half[::-1]
# 如果中间字符为空或等于 'a'
if mid != "":
mid = "z"
right_half = half[::-1]
for i in range(len(right_half)):
cur = right_half[i]
if cur > "a":
new_right = right_half[:i] + chr(ord(cur) - 1) + right_half[i + 1:]
candidate = new_right[::-1] + mid + new_right
if candidate < s:
return candidate
# 如果所有字符都已处理完毕且无法构造满足条件的字符串
return "-1"
详细解释
-
初始化:
n = len(s)获取字符串s的长度。mid = s[n // 2] if n % 2 != 0 else ''计算中间字符(如果n是奇数)。half = s[:n // 2]获取前半部分。
-
处理中间字符:
- 如果
mid不为空且大于'a',尝试将其减1,构造回文字符串并检查是否小于s。 - 如果构造的回文字符串小于
s,直接返回。 - 否则,将
mid设为'z'。
- 如果
-
处理前半部分:
right_half = half[::-1]获取前半部分的逆序。- 从右半部分的末尾开始向前遍历,尝试将每个字符减1,构造回文字符串并检查是否小于
s。 - 如果找到一个合适的字符,构造回文字符串并返回。
- 如果所有字符都已处理完毕且无法构造满足条件的字符串,返回
-1。
通过上述方法,我们可以有效地解决这个问题,并通过测试用例验证其正确性。