演算法設計與分析:K-Similar Strings(Week 5)
阿新 • • 發佈:2018-12-13
學號:16340008
Question:
Strings A
and B
are K
-similar (for some non-negative integer K
) if we can swap the positions of two letters in A
exactly K
times so that the resulting string equals B
.
Given two anagrams A
and B
, return the smallest K
for which A
and B
are K
-similar.
Example 1:
Input: A = "ab", B = "ba" Output: 1
Example 2:
Input: A = "abc", B = "bca"
Output: 2
Example 3:
Input: A = "abac", B = "baca"
Output: 2
Example 4:
Input: A = "aabc", B = "abca"
Output: 2
Note:
1 <= A.length == B.length <= 20
A
andB
contain only lowercase letters from the set{'a', 'b', 'c', 'd', 'e', 'f'}
Answer:
題意是:給A,B兩個字串,在A中兩個字母互相交換,求最少交換多少次後能得到B,即相似度K。首先我們可以知道A,B等長,且A必定能通過有限次字母交換後得到B。因此我們為得到最小交換次數,應保證每次交換能修正至少一個或兩個(若能做到)字母。我們可以從A字串左邊開始,對字母(下標為i)作如下判斷:
- 若A[i] == B[i],即A與B在該下標處相等,則對下一個字母進行判斷。(保證A[0:i] 與 B[0:i]相等)
- 若A[i] != B[i],則在A[i+1:]中找到A[j]與B[i]相同與B[j]不同(否則修正效果為0),記錄所有符合條件的下標j。若A[i]又恰好等於B[j],則可直接交換A[i]和A[j],因為這樣修正效果為2,必是最優的交換之一。交換後,由於A[0:i+1]與B[0:i+1]這i個數相等,因此我們可呼叫函式進行遞迴,對A[i+1:]與B[i+1:]進行對比。呼叫的函式的返回值+1(此次交換)即為所求。
- 定義times為len(A)-1,該times必然大於等於所求次數(只要保證每次交換能修正一個,兩完全不相似的字串在times次交換後可相等)。遍歷記錄的每個j,對每個j作如下操作:交換A[i]與A[j],對A[i+1:]與B[i+1:]呼叫函式本身遞迴,對其返回值+1與times比較求更小值賦值給times。然後重新交換A[i]與A[j],開始下一個j的操作。結束對每個j的操作後返回times。
- 當字串A長度為1時返回0
這裡用到的搜尋思路在於第三步的判斷,對每個有修正意義交換的狀態向下搜尋,因此搜尋的節點上必然字串A與B越來越短,當字串僅剩長度1時返回0(該字串無需交換)。每個節點都對其子節點的返回次數中取最小值,再加一反饋給上層節點。頂層節點對所有返回值對比取最小即可。演算法看似是BFS,然而實際上並不會在得到最小解時便停止搜尋,仍然會搜尋完可能節點後再比較取最小。
以下為程式碼(python3):
class Solution:
def kSimilarity(self, A, B):
"""
:type A: str
:type B: str
:rtype: int
"""
times = 0
for i in range(len(A)-1):
if A[i] == B[i]:
continue
container = []
for j in range(i+1, len(A)):
if A[j] == B[i] and A[j] != B[j]:
container.append(j)
if A[i] == B[j]:
A = A[:i] + A[j] + A[i+1: j] + A[i] + A[j+1:] # swap A[i] and A[j]
return 1 + self.kSimilarity(A[i+1:], B[i+1:])
times = len(A) - 1
for j in container:
A = A[:i] + A[j] + A[i+1: j] + A[i] + A[j+1:] # swap A[i] and A[j]
times = min(times, 1 + self.kSimilarity(A[i+1:], B[i+1:]))
A = A[:i] + A[j] + A[i+1: j] + A[i] + A[j+1:] # swap A[i] and A[j]
return times
return 0
以下程式碼可用於本地測試:
test = Solution()
A = 'aabc'
B = 'abca'
print(test.kSimilarity(A, B))
以下為LeetCode中測試結果: