336. 回文对 [hard]
336. 回文对 [hard]
https://leetcode-cn.com/problems/palindrome-pairs/
给定一组唯一的单词, 找出所有不同 的索引对(i, j),使得列表中的两个单词, words[i] + words[j] ,可拼接成回文串。
示例 1:
输入: ["abcd","dcba","lls","s","sssll"]
输出: [[0,1],[1,0],[3,2],[2,4]]
解释: 可拼接成的回文串为 ["dcbaabcd","abcddcba","slls","llssssll"]
示例 2:
输入: ["bat","tab","cat"]
输出: [[0,1],[1,0]]
解释: 可拼接成的回文串为 ["battab","tabbat"]
通过次数8,149 | 提交次数22,297
First Try
2020-08-06
暴力法O(N^2)果然无法通过,这个是O(N*W), 看题解才了解到的。
对于两个拼接的字符,长度字符肯定在边界处有一个小回文,要么是左侧要么是右侧,去除回文后剩下的部分取反,看是否在字符串列表里,如果存在就能够凑一起。对于两个同样长度的字符,则可以考虑空字符串也是回文,这样就能把两个相等的字符串凑起来。
容易出错的一是需要注意左侧和右侧都需要考虑到;二是对于["a", ""]这种测试样例,需要考虑到在左侧和右侧都能够贴上空字符串,因此需要用range(len(word) + 1) 而不是range(len(word)); 其三是去重重复,但那么多小细节真的不如直接在结果里进行去重。
class Solution:
def palindromePairs(self, words: List[str]) -> List[List[int]]:
"""
bug test:
["abcd","dcba"]
["a", ""]
"""
cache = dict()
for idx, word in enumerate(words):
cache[word] = idx
rv = [ ]
# 只考虑较长的字符串,必有沿着中间合并处的部分字符为回文;如果字符串相等,自空字符串为回文,并不影响
for i, word in enumerate(words):
# 考虑到左侧空字符串和右侧空字符串的两种情况,需要len(word) + 1
# 不然在考虑右边部分为回文的时候,不会出现回文为空;反之考虑左边部分为回文,则可以出现回文为空的情况。 太麻烦了。
for widx in range(len(word) + 1):
# print(widx, word[:widx], word[widx:])
# 右边部分为回文
if word[widx:] == word[widx:][::-1] and word[:widx][::-1] in cache:
j = cache[word[:widx][::-1]]
if j != i:
rv.append([i, j])
# 左边部分为回文
# 这个widx不允许为0存粹为了去重,但综合起来考虑的细节太多了,还不如最终统一在答案列表里去重来得干脆
if widx and word[:widx] == word[:widx][::-1] and word[widx:][::-1] in cache:
j = cache[word[widx:][::-1]]
if j != i:
rv.append([j, i])
return rv
- 执行用时:872 ms, 在所有 Python3 提交中击败了29.68%的用户
- 内存消耗:14.8 MB, 在所有 Python3 提交中击败了89.29%的用户
Time Exceeded Try
2020-08-06
- 暴力法优化版
以为暴力法一不通过是因为使用字符串拼接了,尝试用了非字符串拼接的回文测试,结果速度竟然更慢了。
class Solution:
def palindromePairs(self, words: List[str]) -> List[List[int]]:
# 以为不用字符串拼接算优化,结果速度更慢
print(len(words))
def fast_palindrome(wi, wii):
li, lii = len(wi), len(wii)
lft, rt = 0, li + lii - 1
idx_chr = lambda idx: wi[idx] if idx <= li - 1 else wii[idx - li] # 写成了wii[idx - (li - 1)]
while lft < rt:
if idx_chr(lft) != idx_chr(rt):
return False
lft += 1
rt -= 1
return True
rv = []
for i in range(len(words) - 1):
for j in range(i + 1, len(words)):
if fast_palindrome(words[i], words[j]):
rv.append([i, j])
if fast_palindrome(words[j], words[i]):
rv.append([j, i])
return rv
- 朴素的暴力法,在最长字符串要耗费3s
class Solution:
def palindromePairs(self, words: List[str]) -> List[List[int]]:
# O(N2)算法可能不太行啊, 果然超时了, 4k单词耗时3s
print(len(words))
rv = []
for i in range(len(words) - 1):
for j in range(i + 1, len(words)):
if words[i][0] != words[j][-1] and words[i][-1] != words[j][0]:
continue
wi = words[i] + words[j]
wii = words[j] + words[i]
if wi == wi[::-1]:
rv.append([i, j])
if wii == wii[::-1]:
rv.append([j, i])
return rv