构造回文字符串问题 | 青训营X豆包MarsCode 技术训练营

73 阅读4分钟

构造回文字符串问题解析

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

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

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

问题描述

给定以下参数:

  • 字符串 s:一个只包含小写字母的字符串,长度为 n

我们的目标是构造一个字符串 t,满足上述条件,并输出该字符串。如果无法构造,则输出 -1

输入说明

  • 字符串 s (1 ≤ |s| ≤ 100):只包含小写字母的字符串。

输出说明

  • 输出字符串 t,如果无法构造则输出 -1

测试样例

样例1:

输入

s = "abc"

输出

'aba'

样例2:

输入

s = "cba"

输出

'cac'

样例3:

输入

s = "aaa"

输出

'-1'

示例说明

在样例1中,字符串 s 为 "abc",可以构造回文字符串 t 为 'aba',它的字典序小于 'abc'

在样例2中,字符串 s 为 "cba",可以构造出回文字符串 t 为 'cac',它的字典序小于 'cba'

在样例3中,字符串 s 为 "aaa",无法构造出满足条件的回文字符串,因此输出 -1

解题思路

  1. 回文字符串的特性

    • 回文字符串的前半部分决定了后半部分。例如,字符串 t 的前半部分为 t[0] 到 t[n//2],后半部分为 t[n-1] 到 t[n//2+1]
    • 在构造 t 时,我们可以尝试从 s 的前半部分构造。
  2. 构造过程

    • 将 s 的前半部分复制到 t 的后半部分,形成初始的回文结构。
    • 如果该字符串的字典序已经小于 s,则直接返回。
    • 如果不小于,则需要对前半部分进行调整,使 t 的字典序尽可能大且小于 s
  3. 逐步调整

    • 从字符串 s 的末尾开始,尝试找到第一个可以减小的字符,并进行相应的调整。
    • 如果成功调整,则构造新的回文字符串并返回。
  4. 边界情况

    • 如果字符串 s 是由相同字符组成的字符串(如 "aaa"),则无法构造出更小的回文字符串,直接返回 -1
def construct_palindrome(s: str) -> str:
    n = len(s)
    t = [''] * n
    
    # 构造初始回文字符串
    for i in range((n + 1) // 2):
        t[i] = t[n - 1 - i] = s[i]
        
    # 初始回文字符串
    t = ''.join(t)
    
    # 如果初始回文字符串已经小于 s,直接返回
    if t < s:
        return t
    
    # 从中间向左寻找可以调整的字符
    for i in range((n - 1) // 2, -1, -1):
        if t[i] > 'a':
            # 将当前字符减小
            t = list(t)
            t[i] = t[n - 1 - i] = chr(ord(t[i]) - 1)  # 减小字符
            # 重新构造后半部分的字符
            for j in range(i + 1, (n + 1) // 2):
                t[j] = t[n - 1 - j] = 'z'  # 将后续字符设置为 'z',以确保字典序尽可能大
            
            return ''.join(t)  # 返回构造的回文字符串
            
    # 如果没有找到合适的字符进行调整,输出 -1
    return '-1'

代码解析

  1. 构造初始回文字符串

    • 使用 for 循环将字符串 s 的前半部分复制到新字符串 t 的后半部分,形成初始的回文结构。
    • 这通过 t[i] = t[n - 1 - i] = s[i] 实现,确保 t 是一个回文字符串。
  2. 比较字典序

    • 如果初始构造的回文字符串 t 已经小于 s,直接返回 t
  3. 调整字符

    • 从回文字符串的中间向左遍历,尝试找到第一个大于 'a' 的字符,以便将其减小。
    • 当找到可以减小的字符时,通过 t[i] = chr(ord(t[i]) - 1) 将其减小,并将对应的后半部分字符也进行相同的调整。
    • 为了确保字典序的最大化,将后续字符设置为 'z'
  4. 返回结果

    • 如果找到可行的回文字符串,返回它。如果遍历完整个字符串都没有找到可行的字符进行调整,返回 -1

边界情况处理

  • 相同字符情况:如果字符串 s 由相同字符(如 "aaa")组成,无法构造出更小的回文字符串,因此直接返回 -1
  • 全小写字母情况:如果所有字符都是小写字母且按照升序排列,可能会导致无法构造出符合条件的回文字符串,因此需要在逻辑中处理这种情况。