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

猜你喜欢

转载自blog.csdn.net/Mrfive555/article/details/82811546