📜  字梯 – 设置 2(双向 BFS)

📅  最后修改于: 2021-10-27 06:53:14             🧑  作者: Mango

给定一本字典,两个单词starttarget (长度相同)。如果存在,则查找从开始目标的最小链的长度,使得链中的相邻单词仅相差一个字符,并且链中的每个单词都是有效单词,即存在于字典中。可以假设目标词存在于词典中,并且所有词典词的长度相等。
例子:

方法:这个问题可以使用这里讨论的标准 BFS 方法来解决,但它的性能可以通过使用双向 BFS 来提高。
双向 BFS 不会降低解决方案的时间复杂度,但在许多情况下肯定会优化性能。这种方法也可以用于许多其他最短路径寻找问题,其中我们有足够的关于源节点和目标节点的信息。双向 BFS 的基本思想是从路径的两端开始搜索。
因此,需要维护两个队列和两个访问数组来跟踪这两条路径。因此,每当源队列中存在一个节点(例如 A),遇到目标队列中存在的节点(例如 B)时,我们就可以通过将 A 与源的距离和 B 的距离相加来计算答案从目标减去 1(一个节点是常见的)。通过这种方式,与标准 BFS 方法相比,我们可以用一半的时间来计算答案。这种方法也称为中间相遇 BFS 方法。
下面是上述方法的实现:

C++
// C++ implementation of the approach
#include 
using namespace std;
 
// Structure for queue
struct node {
    string word;
    int len;
};
 
// Function that returns true if a and b
// differ in only a single character
bool isAdj(string a, string b)
{
    int count = 0;
    for (int i = 0; i < a.length(); i++) {
        if (a[i] != b[i])
            count++;
    }
    if (count == 1)
        return true;
    return false;
}
 
// Function to return the length of the shortest
// chain from ‘beginWord’ to ‘endWord’
int ladderLength(string beginWord, string endWord,
                 vector& wordList)
{
 
    /* q1 is used to traverse the graph from beginWord
        and q2 is used to traverse the graph from endWord.
        vis1 and vis2 are used to keep track of the
        visited states from respective directions */
    queue q1;
    queue q2;
    unordered_map vis1;
    unordered_map vis2;
 
    node start = { beginWord, 1 };
    node end = { endWord, 1 };
 
    vis1[beginWord] = 1;
    q1.push(start);
    vis2[endWord] = 1;
    q2.push(end);
 
    while (!q1.empty() && !q2.empty()) {
 
        // Fetch the current node
        // from the source queue
        node curr1 = q1.front();
        q1.pop();
 
        // Fetch the current node from
        // the destination queue
        node curr2 = q2.front();
        q2.pop();
 
        // Check all the neighbors of curr1
        for (auto it = wordList.begin(); it != wordList.end(); it++) {
 
            // If any one of them is adjacent to curr1
            // and is not present in vis1
            // then push it in the queue
            if (isAdj(curr1.word, *it) && vis1.count(*it) == false) {
 
                node temp = { *it, curr1.len + 1 };
                q1.push(temp);
                vis1[*it] = curr1.len + 1;
 
                // If temp is the destination node
                // then return the answer
                if (temp.word == endWord) {
                    return temp.len;
                }
 
                // If temp is present in vis2 i.e. distance from
                // temp and the destination is already calculated
                if (vis2.count(temp.word)) {
                    return temp.len + vis2[temp.word] - 1;
                }
            }
        }
 
        // Check all the neighbors of curr2
        for (auto it = wordList.begin(); it != wordList.end(); it++) {
 
            // If any one of them is adjacent to curr2
            // and is not present in vis1 then push it in the queue.
            if (isAdj(curr2.word, *it) && vis2.count(*it) == false) {
 
                node temp = { *it, curr2.len + 1 };
                q2.push(temp);
                vis2[*it] = curr2.len + 1;
 
                // If temp is the destination node
                // then return the answer
                if (temp.word == beginWord) {
                    return temp.len;
                }
 
                // If temp is present in vis1 i.e. distance from
                // temp and the source is already calculated
                if (vis1.count(temp.word)) {
                    return temp.len + vis1[temp.word] - 1;
                }
            }
        }
    }
    return 0;
}
 
// Driver code
int main()
{
 
    vector wordList;
    wordList.push_back("poon");
    wordList.push_back("plee");
    wordList.push_back("same");
    wordList.push_back("poie");
    wordList.push_back("plie");
    wordList.push_back("poin");
    wordList.push_back("plea");
 
    string start = "toon";
    string target = "plea";
 
    cout << ladderLength(start, target, wordList);
 
    return 0;
}


Java
import java.util.*;
public class GFG
{
public static class node
{
    String word;
    int len;
    public node(String word, int len)
    {
        this.word = word;
        this.len = len;
    }
}
 
public static boolean isAdj(String a, String b)
{
    int count = 0;
    for (int i = 0; i < a.length(); i++)
    {
        if (a.charAt(i) != b.charAt(i))
            count++;
    }
    if (count == 1)
        return true;
    return false;
}
 
// Function to return the length of the shortest
// chain from 'beginWord' to 'endWord'
public static int ladderLength(String beginWord, String endWord,
                               ArrayList wordList)
{
 
    /* q1 is used to traverse the graph from beginWord
        and q2 is used to traverse the graph from endWord.
        vis1 and vis2 are used to keep track of the
        visited states from respective directions */
    Queue q1 = new LinkedList<>();
    Queue q2 = new LinkedList<>();
    HashMap vis1 = new HashMap<>();
    HashMap vis2 = new HashMap<>();
 
    node start = new node(beginWord, 1);
    node end = new node(endWord, 1);
 
    vis1.put(beginWord, 1);
    q1.add(start);
    vis2.put(endWord, 1);
    q2.add(end);
 
    while (q1.size() > 0 && q2.size() > 0)
    {
 
        // Fetch the current node
        // from the source queue
        node curr1 = q1.remove();
 
        // Fetch the current node from
        // the destination queue
        node curr2 = q2.remove();
 
        // Check all the neighbors of curr1
        for (int i = 0; i < wordList.size(); i++)
        {
 
            // If any one of them is adjacent to curr1
            // and is not present in vis1
            // then push it in the queue
            if (isAdj(curr1.word,wordList.get(i)) &&
                vis1.containsKey(wordList.get(i)) == false)
            {
 
                node temp = new node(wordList.get(i),
                                      curr1.len + 1);
                q1.add(temp);
                vis1.put(wordList.get(i), curr1.len + 1);
 
                // If temp is the destination node
                // then return the answer
                if (temp.word.equals(endWord))
                {
                    return temp.len;
                }
 
                // If temp is present in vis2 i.e. distance from
                // temp and the destination is already calculated
                if (vis2.containsKey(temp.word))
                {
                    return temp.len + vis2.get(temp.word) - 1;
                }
            }
        }
 
        // Check all the neighbors of curr2
        for (int i = 0; i < wordList.size(); i++)
        {
 
            // If any one of them is adjacent to curr2
            // and is not present in vis1 then push it in the queue.
            if (isAdj(curr2.word,wordList.get(i)) &&
                vis2.containsKey(wordList.get(i)) == false)
            {
 
                node temp = new node(wordList.get(i),
                                     curr2.len + 1 );
                q2.add(temp);
                vis2.put(wordList.get(i), curr2.len + 1);
 
                // If temp is the destination node
                // then return the answer
                if (temp.word.equals(beginWord))
                {
                    return temp.len;
                }
 
                // If temp is present in vis1 i.e. distance from
                // temp and the source is already calculated
                if (vis1.containsKey(temp.word))
                {
                    return temp.len + vis1.get(temp.word) - 1;
                }
            }
        }
    }
    return 0;
}
 
// Driver code
public static void main(String args[])
{
    ArrayList wordList = new ArrayList<>();
    wordList.add("poon");
    wordList.add("plee");
    wordList.add("same");
    wordList.add("poie");
    wordList.add("plie");
    wordList.add("poin");
    wordList.add("plea");
 
    String start = "toon";
    String target = "plea";
 
    System.out.println(ladderLength(start, target, wordList));
}
}
 
// This code is contributed by Sambhav Jain


C#
// C# implementation of the approach   
using System;
using System.Collections.Generic;
 
class GFG
{
     
class node
{
    public String word;
    public int len;
    public node(String word, int len)
    {
        this.word = word;
        this.len = len;
    }
}
 
public static bool isAdj(String a, String b)
{
    int count = 0;
    for (int i = 0; i < a.Length; i++)
    {
        if (a[i] != b[i])
            count++;
    }
    if (count == 1)
        return true;
    return false;
}
 
// Function to return the length of the shortest
// chain from 'beginWord' to 'endWord'
public static int ladderLength(String beginWord, String endWord,
                            List wordList)
{
 
    /* q1 is used to traverse the graph from beginWord
        and q2 is used to traverse the graph from endWord.
        vis1 and vis2 are used to keep track of the
        visited states from respective directions */
    Queue q1 = new Queue();
    Queue q2 = new Queue();
    Dictionary vis1 = new Dictionary();
    Dictionary vis2 = new Dictionary();
 
    node start = new node(beginWord, 1);
    node end = new node(endWord, 1);
 
    vis1.Add(beginWord, 1);
    q1.Enqueue(start);
    vis2.Add(endWord, 1);
    q2.Enqueue(end);
 
    while (q1.Count > 0 && q2.Count > 0)
    {
 
        // Fetch the current node
        // from the source queue
        node curr1 = q1.Dequeue();
 
        // Fetch the current node from
        // the destination queue
        node curr2 = q2.Dequeue();
 
        // Check all the neighbors of curr1
        for (int i = 0; i < wordList.Count; i++)
        {
 
            // If any one of them is adjacent to curr1
            // and is not present in vis1
            // then push it in the queue
            if (isAdj(curr1.word,wordList[i]) &&
                vis1.ContainsKey(wordList[i]) == false)
            {
 
                node temp = new node(wordList[i],
                                    curr1.len + 1);
                q1.Enqueue(temp);
                vis1.Add(wordList[i], curr1.len + 1);
 
                // If temp is the destination node
                // then return the answer
                if (temp.word.Equals(endWord))
                {
                    return temp.len;
                }
 
                // If temp is present in vis2 i.e. distance from
                // temp and the destination is already calculated
                if (vis2.ContainsKey(temp.word))
                {
                    return temp.len + vis2[temp.word] - 1;
                }
            }
        }
 
        // Check all the neighbors of curr2
        for (int i = 0; i < wordList.Count; i++)
        {
 
            // If any one of them is adjacent to curr2
            // and is not present in vis1 then push it in the queue.
            if (isAdj(curr2.word,wordList[i]) &&
                vis2.ContainsKey(wordList[i]) == false)
            {
 
                node temp = new node(wordList[i],
                                    curr2.len + 1 );
                q2.Enqueue(temp);
                vis2.Add(wordList[i], curr2.len + 1);
 
                // If temp is the destination node
                // then return the answer
                if (temp.word.Equals(beginWord))
                {
                    return temp.len;
                }
 
                // If temp is present in vis1 i.e. distance from
                // temp and the source is already calculated
                if (vis1.ContainsKey(temp.word))
                {
                    return temp.len + vis1[temp.word] - 1;
                }
            }
        }
    }
    return 0;
}
 
// Driver code
public static void Main(String []args)
{
    List wordList = new List();
    wordList.Add("poon");
    wordList.Add("plee");
    wordList.Add("same");
    wordList.Add("poie");
    wordList.Add("plie");
    wordList.Add("poin");
    wordList.Add("plea");
 
    String start = "toon";
    String target = "plea";
 
    Console.WriteLine(ladderLength(start, target, wordList));
}
}
 
// This code is contributed by Rajput-Ji


输出:

7

时间复杂度:O(N^2),其中 N 是字符串的长度。
辅助空间:O(N)。

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程