回溯法还是比较好理解的,但是遗憾自己没有写出来。
class Solution {
public:
int kSimilarity(string A, string B) {
unordered_map<string, int> memo;
return backtrack(A, B, memo, 0);
}
private:
int backtrack(string& A, string& B, unordered_map<string, int>& memo, int i) {//不用i也可以
if (A == B)
return 0;
if (memo.find(A) != memo.end())
return memo[A];
while (i < A.size() && A[i] == B[i])
++i;
int minVal = INT_MAX;
for (int j = i; j < A.size(); ++j) {
if (A[j] == B[i]) {
swap(A[i], A[j]);
int next = backtrack(A, B, memo, i+1);
if (next != INT_MAX)
minVal = min(minVal, next+1);
swap(A[i], A[j]);
}
}
memo[A] = minVal;
return minVal;
}
};
还是那句话,回溯就是试验所有可能性。
还有一个应该想出来的方法,遗憾没有想出来:
class Solution {
public:
int kSimilarity(string A, string B) {
if (A == B)
return 0;
queue<string> q;
unordered_set<string> visited;
q.push(A);
int level = 0;
while (!q.empty()) {
level++;
int sz = q.size();
while (sz--) {
auto str = q.front();
q.pop();
if (visited.find(str) != visited.end())
continue;
visited.insert(str);
int i = 0;
while (i < str.size() && str[i] == B[i])
++i;
//assert(i != str.size());
for (int j = i+1; j < str.size(); ++j) {
if (str[j] == B[i]) {
swap(str[i], str[j]);
if (visited.find(str) != visited.end())
continue;
if (str == B)
return level;
q.push(str);
swap(str[i], str[j]);
}
}//我这里是把第一对不符合的给干掉了,而且全部情况
}//还有其他可能是:把所有可能在一步可以完成的交换全部完成。但是这里没有必要,因为最后总会全部交换完成,这样一步一步是必须的。
}
return 0;
}
};
//最短:想到bfs
//然后怎么算有链接:想到之前有题目是换一个字母相当于有链接
//这里是交换一对字母可以算是有连接