[Leetcode] K-Similar Strings
題目
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
解答
題目要求完成指定的交換所需的最少步數。然而對於怎麼樣才能找到這個最少步數的交換方法,我們沒有任何的先驗經驗,因此,對於這個問題,只能使用遍歷可行空間中所有可行解來實現。因此我們第一個想法是,採用DFS式的遞迴來解決這個問題:
class Solution {
public:
int kSimilarity(string A, string B) {
if (A == B) {
return 0;
}
// 已正確,不用交換。begin記錄第一個錯誤位置
int begin = 0;
while (A[begin] == B[begin]) {
++begin;
}
// A字母可以交換的位置
vector<int> pos;
for (int i = begin + 1; i != A.size(); ++i) {
if (B[begin] == A[i]) {
pos.push_back(i);
}
}
int minTime = INT_MAX;
for (auto p : pos) {
swap(A[begin], A[p]);
int time = kSimilarity(A.substr(begin + 1), B.substr(begin + 1));
if (time < minTime) {
minTime = time + 1;
}
swap(A[begin], A[p]);
}
return minTime;
}
};
遞迴的思路是每次把一個正確的字元前移到A字串的頭部,k-similar問題就將變為一個規模更小的(k-1)-similar問題。在程式碼中,我們引入了vector<int>
型的pos變數,這個變數儲存A頭部可以交換到的所有位置。
然而這種這份程式碼現在並不能很好的工作–即使是DFS本身,已經出現了大量的可行解,而在搜尋這些可行解的過程中,有很多狀態時被重複搜尋的,這種重複帶來了大量的時間浪費。這啟發我們應該使用一個容器,記錄下已經遍歷過的狀態,這裡我們使用一個雜湊表:unordered_map
class Solution {
private:
unordered_map<string, int> solution;
public:
int kSimilarity(string A, string B) {
if (A == B) {
return 0;
}
if (solution[A + B]) {
return solution[A + B];
}
// 已正確,不用交換。begin記錄第一個錯誤位置
int begin = 0;
while (A[begin] == B[begin]) {
++begin;
}
// A字母可以交換的位置
vector<int> pos;
for (int i = begin + 1; i != A.size(); ++i) {
if (B[begin] == A[i]) {
pos.push_back(i);
}
}
int minTime = INT_MAX;
for (auto p : pos) {
swap(A[begin], A[p]);
int time = kSimilarity(A.substr(begin + 1), B.substr(begin + 1));
if (time < minTime) {
minTime = time + 1;
}
swap(A[begin], A[p]);
}
solution[A + B] = minTime;
return minTime;
}
};
讀者可能會注意到,這裡我們直接使用了字串A+B作為雜湊表的鍵,這事實上是對儲存空間的一個極大的浪費,因此,網上提出了一種使用long代替string的演算法(C++ DFS + DP + string encoding with detailed explanation, beats 88.71%)。但上述演算法已經能通過題解,此處不作繼續優化。