构造回文字符串问题 | 豆包MarsCode AI刷题

3 阅读6分钟

思考思路

  1. 回文特性:回文字符串的特点是前半部分和后半部分对称。因此,我们可以通过处理字符串的前半部分来构造整个回文字符串。
  2. 字典序比较:为了使 t 的字典序小于 s,我们需要在前半部分找到一个位置,使得该位置的字符可以减小,并且构造的回文字符串仍然有效。
  3. 尽可能大的字典序:在找到可以减小的字符后,我们需要确保减小后的字符尽可能大,以满足字典序尽可能大的要求。

代码思路

  1. 检查是否可能构造回文:如果字符串 s 的所有字符都相同且为 'a',则无法构造满足条件的回文字符串。

  2. 构造回文

    • 从字符串的中间向两边检查,找到第一个可以减小的字符。
    • 减小该字符,并构造回文字符串。
    • 如果减小后的字符仍然大于 s 的对应字符,则继续减小,直到找到满足条件的字符。

代码实现



def solution(s: str) -> str:
    n = len(s)
    t = list(s)  # 转换为列表,方便修改
    
    # 先构建一个回文字符串
    for i in range(n // 2):
        t[n - i - 1] = t[i]  # 保持回文性

    # 如果初始回文字符串已经小于s,直接返回
    if ''.join(t) < s:
        return ''.join(t)
    
    # 否则,从中间开始向前调整
    for i in range((n - 1) // 2, -1, -1):
        if t[i] > 'a':  # 如果当前字符大于 'a',可以减小
            t[i] = chr(ord(t[i]) - 1)
            t[n - i - 1] = t[i]  # 保持回文性
            # 调整后面的位置为尽可能的小字符 'z',确保字典序最小
            for j in range(i + 1, n - i - 1):
                t[j] = 'z'
                t[n - j - 1] = t[j]
            # 生成回文字符串并检查字典序
            t_str = ''.join(t)
            if t_str < s:
                return t_str
            else:
                # 如果调整后仍然不满足条件,继续尝试下一个字符
                t[i] = s[i]
                t[n - i - 1] = t[i]
    
    return '-1'


# 测试用例
if __name__ == '__main__':
    print(solution("abc") == 'aba')  # 输出 'aba'
    print(solution("cba") == 'cac')  # 输出 'cac'
    print(solution("aaa") == '-1')  # 输出 '-1'

代码详解

1. 函数定义

def solution(s: str) -> str:

定义了一个名为 solution 的函数,它接受一个字符串参数 s,并返回一个字符串。

2. 初始化相关变量

n = len(s)
t = list(s)  # 转换为列表,方便修改
  • n = len(s):计算输入字符串 s 的长度,并将其存储在变量 n 中。

  • t = list(s):将输入字符串 s 转换为字符列表 t。这样做是因为在 Python 中,字符串是不可变的,将其转换为列表后可以方便地对其中的字符进行修改操作。

3. 构建一个回文字符串

for i in range(n // 2):
    t[n - i - 1] = t[i]  # 保持回文性

通过循环遍历字符串的前半部分(range(n // 2)),将后半部分的对应位置字符设置为与前半部分相同,从而构建出一个回文字符串。例如,如果输入字符串是 "abc",经过这一步操作后,列表 t 变为 ['a', 'b', 'a']

4. 检查初始回文字符串是否小于输入字符串

if ''.join(t) < s:
    return ''.join(t)

将字符列表 t 通过 ''.join(t) 转换回字符串,并与输入字符串 s 进行比较。如果构建的回文字符串小于输入字符串 s,则直接返回该回文字符串。这是因为题目要求找到比输入字符串小的字典序最小的回文串,所以如果已经满足小于的条件,就找到了答案。

5. 从中间开始向前调整回文字符串(当上述条件不满足时)

for i in range((n - 1) // 2, -1, -1):
    if t[i] > 'a':  # 如果当前字符大于 'a',可以减小
        t[i] = chr(ord(t[i]) - 1)
        t[n - i - 1] = t[i]  # 保持回文性
        # 调整后面的位置为尽可能的小字符 'z',确保字典序最小
        for j in range(i + 1, n - i - 1):
            t[j] = 'z'
            t[n - j - 1] = t[j]
        # 生成回文字符串并检查字典序
        t_str = ''.join(t)
        if t_str < s:
            return t_str
        else:
            # 如果调整后仍然不满足条件,继续尝试下一个字符
            t[i] = s[i]
            t[n - i - 1] = t[i]
  • 外层循环 for i in range((n - 1) // 2, -1, -1):从字符串的中间位置(如果字符串长度为奇数,就是正中间的字符;如果是偶数,就是中间偏左的字符)开始,向字符串的开头方向遍历。这样做的目的是尝试从中间位置开始逐个调整字符,以找到满足条件的字典序更小的回文串。

  • if t[i] > 'a'::检查当前位置 i 的字符是否大于 'a'。如果大于 'a',就可以通过将其减小来尝试构建更小的回文串。

  • t[i] = chr(ord(t[i]) - 1):将当前位置 i 的字符通过 ord() 函数获取其 ASCII 码值,然后减 1,再通过 chr() 函数将新的 ASCII 码值转换回字符,从而实现将该字符减小的操作。例如,如果当前字符是 'b',经过这一步就会变为 'a'

  • t[n - i - 1] = t[i]:保持回文性,将后半部分对应位置的字符也设置为与调整后的前半部分字符相同。

  • 内层循环 for j in range(i + 1, n - i - 1):在调整了当前位置 i 的字符后,将当前位置后面到后半部分对应位置之前的字符都设置为 'z'。这是为了在保证回文性的前提下,让这些位置的字符尽可能小,从而使整个回文串的字典序更小。

  • t_str = ''.join(t):将调整后的字符列表 t 转换回字符串,以便与输入字符串 s 进行比较。

  • if t_str < s::如果调整后的字符串小于输入字符串 s,则找到了满足条件的字典序更小的回文串,直接返回该字符串。

  • else::如果调整后的字符串不小于输入字符串 s,说明这次调整不成功,需要将当前位置 i 的字符恢复为原来输入字符串 s 中的字符(t[i] = s[i]),并将后半部分对应位置的字符也恢复(t[n - i - 1] = t[i]),然后继续尝试下一个位置的字符调整。

6. 返回结果

return '-1'

如果经过上述所有尝试都没有找到满足条件的字典序更小的回文串,就返回 '-1',表示不存在这样的回文串。

最后,在 if __name__ == '__main__': 部分是一些测试用例,用于验证 solution 函数的功能是否正确。例如,通过 print(solution("abc") == 'aba') 等语句来检查函数对于不同输入字符串的输出是否符合预期。