📌  相关文章
📜  将字符串X 转换为 Y 的最少点击次数

📅  最后修改于: 2021-10-25 05:05:31             🧑  作者: Mango

给定的3个字符的起始字符串X,精加工的3个字符的字符串Y和禁止字符串数组。任务是找到从 X 到达 Y 的最小点击次数。

规则:

  • 3 个字符中的每一个都以循环方式变化,即在每次点击时,您可以从a 到 b或从a 到 z,并且不会显示任何禁用词。
  • 如果无法到达 Y ,则打印 -1 每次单击时,只能更改一个字母。
  • 每个禁用字符串的格式为:{ “S1”“S2”“S3”} ,其中每个字符串S i包含该字符的禁用字母。
  • Forbidden 字符串 = {“ac” “bx” “lw”}表示禁止使用“abl”、“cxw”、“cbl”、“abw”、“cbw”、“axl”、“axw”和“cxl”永远不会显示。

    注意:如果起始字符串X 也是禁用字符的可能组合,那么结果也应该是 -1。

    方法:

    使用 BFS(广度优先搜索)并进行某些修改以获得最小点击次数,绕过禁止字符串。

    1. 由于这 3 个位置中的每一个都可以包含字母,因此创建一个维度为 26 * 26 * 26 的 3D 访问数组以遍历单词状态。
    2. 为了可视化每个受限制的单词,创建另一个 26 * 26 * 26 维度的 3D 数组,以跟踪在遍历中绝不能访问的单词。
    3. 由于这 3 个字符中的每一个都以循环方式变化,即每次单击时字母都会以圆形方式变化,因此每次到达下一个字母时都需要注意对 26 取模。
    4. 令单词的当前状态为[XYZ] 。然后单击即可移动到以下 6 种状态:
    5. 因此,创建 3 个实用程序数组dx, dy, dz以保持遍历过程的简化。将每个单词状态存储在具有 4 个字段的结构体中,即 a、b、c(3 个字符的每一个)以及与起始单词的距离。

    下面是上述方法的实现:

    C++
    // C++ code for above program.
    #include 
    using namespace std;
    #define int long long int
      
    // each node represents a word state
    struct node {
        int a, b, c;
        // dist from starting word X
        int dist;
    };
      
    // 3D visited array
    bool visited[26][26][26];
      
    // 3D restricted array
    bool restricted[26][26][26];
      
    // utility arrays for single step
    // traversal in left and right
    int dx[6] = { 1, -1, 0, 0, 0, 0 };
    int dy[6] = { 0, 0, 1, -1, 0, 0 };
    int dz[6] = { 0, 0, 0, 0, 1, -1 };
      
    // function to find the
    // minimum clicks.
    void solve(string start,
               string end, int qx,
               const vector >& forbidden)
    {
      
        memset(visited, 0,
               sizeof(visited));
        memset(restricted, 0,
               sizeof(restricted));
      
        for (auto vec : forbidden) {
      
            string a = vec[0];
            string b = vec[1];
            string c = vec[2];
      
            for (auto x : a)
                for (auto y : b)
                    for (auto z : c) {
      
                        // each invalid word is
                        // decoded and marked as
                        // restricted = true.
                        restricted[x - 'a']
                                  [y - 'a']
                                  [z - 'a']
                            = true;
                    }
        }
      
        // starting and ending letter a
        int sa = start[0] - 'a';
        int ea = end[0] - 'a';
      
        // starting and ending letter b
        int sb = start[1] - 'a';
        int eb = end[1] - 'a';
      
        // starting and ending letter c
        int sc = start[2] - 'a';
        int ec = end[2] - 'a';
      
        if (restricted[sa][sb][sc]
            or restricted[ea][eb][ec]) {
      
            // check if starting word
            // or finishing word is
            // restricted or not
            cout << -1 << endl;
      
            return;
        }
      
        // queue of nodes for BFS
        queue q;
      
        // initial starting word pushed in
        // queue. dist = 0 for starting word
        q.push({ sa, sb, sc, 0 });
      
        // mark as visited
        visited[sa][sb][sc] = true;
      
        while (!q.empty()) {
            node x = q.front();
            q.pop();
      
            // final destination reached condition
            if (x.a == (end[0] - 'a')
                and x.b == (end[1] - 'a')
                and x.c == (end[2] - 'a')) {
      
                cout << x.dist
                     << endl;
                return;
            }
      
            int DIST = x.dist;
            for (int i = 0; i < 6; i++) {
      
                // mod 26 for circular letter sequence
      
                // next letter for a
                int A = (x.a + dx[i] + 26) % 26;
      
                // next letter for b
                int B = (x.b + dy[i] + 26) % 26;
      
                // next letter for c
                int C = (x.c + dz[i] + 26) % 26;
      
                if (!restricted[A][B][C]
                    and !visited[A][B][C]) {
      
                    // if a valid word state,
                    // push into queue
                    q.push({ A, B, C, DIST + 1 });
                    visited[A][B][C] = true;
                }
            }
        }
      
        // reach here if not possible
        // to reach final word Y
        cout << -1 << endl;
    }
      
    // Driver Code
    signed main()
    {
        // starting string
        string X = "znw";
      
        // final string
        string Y = "lof";
      
        // no of restricting word vectors
        int N = 4;
      
        vector > forbidden
            = { { "qlb", "jcm", "mhoq" },
                { "azn", "piy", "vj" },
                { "by", "oy", "ubo" },
                { "jqm", "f", "ej" } };
      
        solve(X, Y, N, forbidden);
        return 0;
    }


    输出:
    22
    


    时间复杂度: O(26 * 26 * 26),因为最多可以有 26*26*26 个字状态。
    空间复杂度: O(26 * 26 * 26)