給定兩個等長字符串 s1, s2,判斷 s2 是否為 s1 的「擾亂字符串」。擾亂操作定義為:將字符串遞歸二分,任意非葉節點交換左右子樹。
擾亂相當於在二叉樹分割表示中交換子樹。判斷 s2 是否可由 s1 經過若干次交換得到,等價於:存在某個分割點 k (1 ≤ k < n),使得以下兩種情況之一成立:
map<pair<string,string>, bool> 記錄已計算結果,避免重複計算,將指數複雜度降至多項式。class Solution:
def __init__(self):
self.memo = {}
def isScramble(self, s1: str, s2: str) -> bool:
if (s1, s2) in self.memo:
return self.memo[(s1, s2)]
if s1 == s2:
self.memo[(s1, s2)] = True
return True
if sorted(s1) != sorted(s2): # 剪枝:字符集不同
self.memo[(s1, s2)] = False
return False
n = len(s1)
for i in range(1, n):
# 情況一:不交換
if self.isScramble(s1[:i], s2[:i]) and self.isScramble(s1[i:], s2[i:]):
self.memo[(s1, s2)] = True
return True
# 情況二:交換
if self.isScramble(s1[:i], s2[n-i:]) and self.isScramble(s1[i:], s2[:n-i]):
self.memo[(s1, s2)] = True
return True
self.memo[(s1, s2)] = False
return False
無備忘錄時為指數級。加入備忘錄後,狀態數為 O(n^4) (所有子串對),每狀態 O(n) 窮舉分割點,總時間 O(n^5),空間 O(n^4)。實際運行極快。