# Word Ladder – Set 2 ( Bi-directional BFS )

• Difficulty Level : Expert
• Last Updated : 01 Dec, 2021

Given a dictionary, and two words start and target (both of the same length). Find length of the smallest chain from start to target if it exists, such that adjacent words in the chain only differ by one character and each word in the chain is a valid word i.e., it exists in the dictionary. It may be assumed that the target word exists in the dictionary and the lengths of all the dictionary words are equal.
Examples:

Input: Dictionary = {POON, PLEE, SAME, POIE, PLEA, PLIE, POIN}
start = “TOON”
target = “PLEA”
Output:
TOON -> POON –> POIN –> POIE –> PLIE –> PLEE –> PLEA

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.  To complete your preparation from learning a language to DS Algo and many more,  please refer Complete Interview Preparation Course.

In case you wish to attend live classes with experts, please refer DSA Live Classes for Working Professionals and Competitive Programming Live for Students.

Approach: This problem can be solved using the standard BFS approach as discussed here but its performance can be improved by using bi-directional BFS.
Bi-directional BFS doesn’t reduce the time complexity of the solution but it definitely optimizes the performance in many cases. This approach can also be used in many other shortest pathfinding problems where we have sufficient information about the source and the target node. The basic idea involved in bi-directional BFS is to start the search from both the ends of the path.
Therefore, two queues and two visited arrays are needed to be maintained to track both the paths. So, whenever a node (say A) is present in the source queue, encounters a node (say B) which is present in the target queue, then we can calculate the answer by adding the distance of A from source and the distance of B from target minus 1 (one node is common). This way we can calculate the answer in half the time as compared to the standard BFS approach. This method is also known as the meet-in-the-middle BFS approach.
Below is the implementation of the above approach:

## C++

 // C++ implementation of the approach#include using namespace std; // Structure for queuestruct node {    string word;    int len;}; // Function that returns true if a and b// differ in only a single characterbool 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 codeint 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;}

## Python3

 # Python 3 implementation of the approachfrom collections import deque as dq # class for queueclass node :    def __init__(self, w, l):        self.word=w        self.len=l  # Function that returns true if a and b# differ in only a single characterdef isAdj(a, b):    count = 0    for i in range(len(a)):        if (a[i] != b[i]):            count+=1         if (count == 1):        return True    return False  # Function to return the length of the shortest# chain from ‘beginWord’ to ‘endWord’def ladderLength(beginWord, endWord, 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    q1=dq([])    q2=dq([])    vis1=dict()    vis2=dict()     start = node(beginWord, 1)    end = node(endWord, 1)     vis1[beginWord] = 1    q1.append(start)    vis2[endWord] = 1    q2.append(end)     while (q1 and q2):         # Fetch the current node        # from the source queue        curr1 = q1.popleft()         # Fetch the current node from        # the destination queue        curr2 = q2.popleft()         # Check all the neighbors of curr1        for it in wordList:             # 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) and it not in vis1) :                 temp = node(it, curr1.len + 1)                q1.append(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 temp.word in vis2 :                    return temp.len + vis2[temp.word] - 1                                                # Check all the neighbors of curr2        for it in wordList:             # 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) and it not in vis2) :                 temp = node(it, curr2.len + 1)                q2.append(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 temp.word in vis1:                    return temp.len + vis1[temp.word] - 1              return 0  # Driver codeif __name__=='__main__':     wordList=[]    wordList.append("poon")    wordList.append("plee")    wordList.append("same")    wordList.append("poie")    wordList.append("plie")    wordList.append("poin")    wordList.append("plea")     start = "toon"    target = "plea"     print(ladderLength(start, target, wordList))
Output:
7

Time Complexity: O(N^2), where N is the length of the string.
Auxiliary Space: O(N).

My Personal Notes arrow_drop_up