這兩兩組合會有前後順序的差異,如果用最直觀的暴力破解法,跑遍每個組合,時間複雜度會是 O(n*(n-1)),O(n**2)。
列在 trie 的範圍內,這提示我們要使用 trie 去建立搜尋樹。要如何建立能找出回文的 trie ?
想一下回文的特性,如果是回文,頭跟尾會是相等的,頭跟尾往中間移動的字也會兩兩相等。
abcd|dcba, s|lls, lls|sssll => abcd|abcd., s|s.ll, lls|lls.ss
如果用顛倒的字詞建立 trie ,在搜尋過程中就可以前尾兩兩對消,如果過程找到字詞,只要確保「 . 」之後找到底也是回文的就可以。
aa|a => a.a|a.
萬一輸入的字詞找完之前,就先找到比較短的顛倒字詞,也代表後面不會再有字可以添加,先後對消後,只需要針對搜尋詞還沒找部分做回文判斷即可。
class Solution:
def palindromePairs(self, words): result = [] if words: trie = {} #反向 # create Trie n = len(words) for i in range(n): cur = trie for char in words[i][::-1]: if char not in cur: cur[char] = {} cur = cur[char] cur['end'] = i # 檢查對稱 def isSymmetry(word): n = len(word) for i in range(n//2): if word[i] != word[n-1-i]: return False return True # def search1(idx, temp, cur): """搜尋當前字詞""" if temp: # 如果過程中找到字詞,檢查當前的剩餘部分是否回文 if 'end' in cur and isSymmetry(temp) and idx != cur['end']: result.append([idx, cur['end']]) if temp[0] in cur: search1(idx, temp[1:], cur[temp[0]]) else: search2(idx, "", cur) def search2(idx, temp, cur): """搜尋剩餘部分是否回文""" for key in cur: if key == "end": if isSymmetry(temp) and idx != cur['end']: result.append([idx, cur['end']]) else: search2(idx, temp+key, cur[key]) # for i in range(n): search1(i, words[i], trie) return result
在效率上還是太慢,我搜尋是用更廣的對稱,涵蓋更多的可能性。看了一下前段班的寫法,去找更好的思路。
如果在搜尋上,是把字文拆出「可能」組合成回文的部分搜尋,就能提升效率,但我那時有思考到這種方式,但沒有寫想到要怎麼寫,因為我trie總是用成一層層,所以被侷限了。
字詞可以整個直接當成字典的鍵使用,該鍵的值就是位置。
像是 abcd,如果要拆成回文形式,就得找出左右之分。
abcd 前組後:
abcd | "" => ""是回文 => dcba(前面部分反序) => [0,1] #前組後
abc | d => d是回文 => cba => not found
ab | cd => cd不是回文 => X
a | bcd => cbd不是回文 => X
"" | abcd => abcd不是回文 => X
換個字詞
s 前組後:
s | "" => ""是回文 => s => [3,3] => 不合規則
"" | s => s是回文 => "" => not found
lls 前組後:
lls | "" => ""是回文 => sll => not found
ll | s =>> s是回文 => ll => not found
l | ls => ls不是回文 => X
"" | lls => lls不是回文 => X
這樣的搜尋只有「前組後」,沒有考慮到「後組前」,要考慮 後組前 只要把字詞反序做搜尋。
lls 後組前:
sll(字詞反序) | "" => ""是回文 => lls => [2,2] => 不合規則
sl | l => l是回文 => ls => not found
s | ll => ll是回文 => s => [3,2] #後組前
"" | sll => sll不是回文 => X
這樣搜尋速度快不少,不過會有答案會重複,所以要想辦法去掉。
class Solution: def palindromePairs(self, words): table = dict(map(reversed, enumerate(words))) res = set() for i, word in enumerate(words): for k in range(len(word)+1): a = word[:k] b = word[k:] if a == a[::-1] and table.get(b[::-1], i) not in [-1, i]: res.add((table.get(b[::-1], -1), i)) if b == b[::-1] and table.get(a[::-1], i) not in [-1, i]: res.add((i, table.get(a[::-1], -1))) return list(res)