题目
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%)。但上述算法已经能通过题解,此处不作继续优化。