[Week 5] LeetCode 854. K-Similar Strings

LeetCode 854. 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

Note:

  1. 1 <= A.length == B.length <= 20
  2. A and B contain only lowercase letters from the set {'a', 'b', 'c', 'd', 'e', 'f'}

题解:

Ok,一上来我们当然可以想到暴力DFS一下啦,走一步是一步,总能走到的是吧,但是仔细想想,这样会产生一些无用的状态呀,例如交换了一些没有必要交换的位置,这样肯定是相当耗时的。嗯,仔细审审题,要最少的交换来完成,最少,最短,没错——就是BFS了。

算法思想为:首先拿到初始节点A,寻找其子节点,作为BFS搜索树的第二层,接着第二层的节点的子节点作为第三层…

那么怎么寻找其子节点呢,我们可以通过从左往右扫描当前节点字符串和目标节点B,找到第一个不同字母的位置,然后接着扫描该位置后面的字母,找到满足:

  • current_node[i] == B[p],p为上面找到的不同字母的位置
  • current_node[i] != B[p]

的坐标iswap后先判断是否已经访问过该状态(通过set visited),没访问过才压入队列作为子节点。(为什么要满足第二个条件呢,因为已经相同字母的位置就没有必要去交换了不是吗?)

举个栗子:

当前节点为abcbba,目标节点Babbbac,那么我们可以找到这么两个子节点:abbcbaabbbca

Code:

class Solution {
public:
    int kSimilarity(string A, string B) {

        queue<string> q;
        set<string> visited;
        int count = 0;

        q.push(A);
        visited.insert(A);
        while (!q.empty()) {
            // then we don't need two queue for different level nodes
            int cur_level_que_size = q.size();

            for (int i = 0; i < cur_level_que_size; ++i) {
                string s = q.front();
                q.pop();

                // current pos of inequal letter
                int p = 0;
                while (s[p] == B[p] && p < s.length()) ++p;
                if (p == s.length()) return count;

                for (int j = p + 1; j < s.length(); ++j) {
                    if (s[j] == B[j] || s[j] != B[p]) continue;
                    if (s[j] == B[p]) {
                        string tmp = swap(s, j, p);
                        if (!visited.count(tmp)) {
                            q.push(tmp);
                            visited.insert(tmp);
                        }
                    }
                }
            }

            ++count;
        }

        return count;
    }

private:
    string swap(string s, int x, int y) {
        char c = s[x];
        s[x] = s[y];
        s[y] = c;
        return s;
    }
};

复杂度:

这个算法的复杂度实在不那么好分析,只能说相比DFS,其搜索会更有效率,因为我们在探索每层子节点时,会排除不少的状态,虽说DFS也能用相同的策略,但从直觉上来说,BFS确实是看起来更有效率的方式。

菜哭,逃

你可能感兴趣的:(c++,bfs,算法,LeetCode,Graph)