Skip to main content

336.回文对

标签: trie, string, hash-table

难度: Hard

通过率: 35.82%

原题链接: https://leetcode.com/problems/palindrome-pairs/description/

题目描述

你得到一个0索引的独特字符串数组words。一个回文对是指一对整数(i, j),满足:0 <= i, j < words.length, i != j, 并且words[i] + words[j](两个字符串的连接)是一个回文。返回所有回文对的数组。你的算法必须具有O(sum of words[i].length)的运行时间复杂度。

解题思路

解决此问题的关键是有效地检查两个字符串的连接是否是回文。我们可以借助于字典树(Trie)来更高效地查找和匹配回文。考虑到多个字符串,会有以下几类策略来寻找回文对:

  1. 根据回文的定义,若prefix+str+suffixprefix + str + suffix是回文,则prefixprefixsuffixsuffix同时是回文。所以我们可以拆分每个字符串,检查分割点两边是否可以形成回文。

  2. 对于每个单词,将其逆序作为键存储在字典树中,这样可以快速找到某个前缀或后缀的反转。

  3. 遍历每一个字符串,对每个可能的切分点,检查该字符串分割的前缀是否是回文,同时在字典树中寻找其后缀的反转,以及检查后缀是否是回文并寻找其前缀的反转。

  4. 特别地,如果字符串为空,那么其他每一个单个字符均可以形成回文。

通过上述策略,我们可以在遍历字符串的过程中,借助字典树快速判断和匹配可能的回文对,从而达到预期的时间复杂度。

代码实现

class Solution:
def palindromePairs(self, words: List[str]) -> List[List[int]]:
# 构建字典,存储每个单词的逆序及索引
lookup = {word[::-1]: i for i, word in enumerate(words)}
res = []

for i, word in enumerate(words):
for j in range(len(word) + 1):
# 拆分字符串成prefix和suffix
prefix, suffix = word[:j], word[j:]

# 如果prefix是回文,那么suffix的逆序应该在lookup中
if prefix == prefix[::-1] and suffix in lookup and lookup[suffix] != i:
res.append([lookup[suffix], i])

# 如果suffix是回文,那么prefix的逆序应该在lookup中,避免重复,我们略过j==0的情况
if j != len(word) and suffix == suffix[::-1] and prefix in lookup and lookup[prefix] != i:
res.append([i, lookup[prefix]])

return res

复杂度分析

时间复杂度为 O(nk2)O(n \, k^2),其中 nn 是单词数量,kk 是单词的最大长度。因为对于每个单词,我们在为每个长度迭代进行分割并检查前缀和后缀是否为回文。

空间复杂度为 O(nk)O(n \, k),用于存储每个单词的逆序和字典树的构建。