Open In App

Print all possible shortest chains to reach a target word

Improve
Improve
Like Article
Like
Save
Share
Report

Given two strings start and target(both of the same length) and a list of strings str[], the task is to print all possible smallest sequences starting from start to target if it exists, such that adjacent words in the sequence only differ by a single character and each word in the sequence is present in the given list. 

Note: It may be assumed that the target word is present in the list and the length of all the words is the same. If multiple sequences occur, print all of them.

Example:

Input: str[] = {poon, plee, same, poie, plea, plie, poin}, start = “toon”, target = “plea”
Output: [[toon, poon, poin, poie, plee, plea]]
Explanation: toon ? poon ? poin ? poie ? plee ? plea

Input: str[] = { ted, tex, red, tax, tad, den, rex, pee}, start = “red”, target = “tax”
Output [[“red”, “ted”, “tad”, “tax”], [“red”, “ted”, “tex”, “tax”], [“red”, “rex”, “tex”, “tax”]]

Approach: The problem can be solved using BFS.The tricky part here is to do the BFS of the path instead of words. Follow the steps below to solve the problem:

  1. Initialize a variable, say res, to store all possible shortest paths.
  2. Create a Set to store all the visited words in current path and once the current path is completed, erase all the visited words.
  3. For each current word, find the possible next words present in str[] by changing each character from ‘a’ to ‘z’ and find all possible paths.
  4. Finally, print all the possible path.

C++




// C++ Program to implement
// the above approach
#include <bits/stdc++.h>
using namespace std;
 
// Function to print all possible shortest
// sequences starting from start to target.
void displaypath(vector<vector<string> >& res)
{
    for (int i = 0; i < res.size(); i++) {
        cout << "[ ";
        for (int j = 0; j < res[0].size(); j++) {
            cout << res[i][j] << ", ";
        }
        cout << " ]\n";
    }
}
// Find words differing by a single
// character with word
vector<string> addWord(
    string word,
    unordered_set<string>& dict)
{
    vector<string> res;
 
    // Find next word in dict by changing
    // each element from 'a' to 'z'
    for (int i = 0; i < word.size(); i++) {
        char s = word[i];
        for (char c = 'a'; c <= 'z'; c++) {
            word[i] = c;
            if (dict.count(word))
                res.push_back(word);
        }
        word[i] = s;
    }
    return res;
}
 
// Function to get all the shortest possible
// sequences starting from 'start' to 'target'
vector<vector<string> > findLadders(
    vector<string>& Dict,
    string beginWord,
    string endWord)
{
    // Store all the shortest path.
    vector<vector<string> > res;
 
    // Store visited words in list
    unordered_set<string> visit;
 
    // Queue used to find the shortest path
    queue<vector<string> > q;
 
    // Stores the distinct words from given list
    unordered_set<string> dict(Dict.begin(),
                               Dict.end());
    q.push({ beginWord });
 
    // Stores whether the shortest
    // path is found or not
    bool flag = false;
 
    while (!q.empty()) {
        int size = q.size();
        for (int i = 0; i < size; i++) {
 
            // Explore the next level
            vector<string> cur = q.front();
            q.pop();
            vector<string> newadd;
 
            // Find words differing by a
            // single character
            newadd = addWord(cur.back(), dict);
 
            // Add words to the path.
            for (int j = 0; j < newadd.size(); j++) {
                vector<string> newline(cur.begin(),
                                       cur.end());
 
                newline.push_back(newadd[j]);
 
                // Found the target
                if (newadd[j] == endWord) {
                    flag = true;
                    res.push_back(newline);
                }
 
                visit.insert(newadd[j]);
                q.push(newline);
            }
        }
 
        // If already reached target
        if (flag) {
            break;
        }
 
        // Erase all visited words.
        for (auto it : visit) {
            dict.erase(it);
        }
 
        visit.clear();
    }
    return res;
}
 
// Driver Code
int main()
{
    vector<string> str{ "ted", "tex", "red",
                        "tax", "tad", "den",
                        "rex", "pee" };
    string beginWord = "red";
    string endWord = "tax";
 
    vector<vector<string> > res
        = findLadders(str, beginWord, endWord);
 
    displaypath(res);
}


Java




import java.util.*;
 
public class ShortestSequence
{
   
    // Function to print all possible shortest
    // sequences starting from start to target.
    public static void displaypath(List<List<String> > res)
    {
        for (List<String> list : res) {
            System.out.print("[ ");
            for (String word : list) {
                System.out.print(word + ", ");
            }
            System.out.println(" ]");
        }
    }
 
    // Find words differing by a single
    // character with word
    public static List<String> addWord(String word,
                                       Set<String> dict)
    {
        List<String> res = new ArrayList<>();
 
        // Find next word in dict by changing
        // each element from 'a' to 'z'
        char[] chars = word.toCharArray();
        for (int i = 0; i < word.length(); i++) {
            char original = chars[i];
            for (char c = 'a'; c <= 'z'; c++) {
                chars[i] = c;
                String newWord = new String(chars);
                if (dict.contains(newWord)) {
                    res.add(newWord);
                }
            }
            chars[i] = original;
        }
        return res;
    }
 
    // Function to get all the shortest possible
    // sequences starting from 'start' to 'target'
    public static List<List<String> >
    findLadders(List<String> dict, String beginWord,
                String endWord)
    {
        // Store all the shortest path.
        List<List<String> > res = new ArrayList<>();
 
        // Store visited words in list
        Set<String> visit = new HashSet<>();
 
        // Queue used to find the shortest path
        Queue<List<String> > q = new LinkedList<>();
 
        // Stores the distinct words from given list
        Set<String> words = new HashSet<>(dict);
        q.add(Collections.singletonList(beginWord));
 
        // Stores whether the shortest
        // path is found or not
        boolean flag = false;
 
        while (!q.isEmpty()) {
            int size = q.size();
            for (int i = 0; i < size; i++) {
                // Explore the next level
                List<String> cur = q.poll();
                List<String> newWords = addWord(
                    cur.get(cur.size() - 1), words);
 
                // Add words to the path.
                for (String newWord : newWords) {
                    List<String> newLine
                        = new ArrayList<>(cur);
                    newLine.add(newWord);
 
                    // Found the target
                    if (newWord.equals(endWord)) {
                        flag = true;
                        res.add(newLine);
                    }
 
                    visit.add(newWord);
                    q.add(newLine);
                }
            }
 
            // If already reached target
            if (flag) {
                break;
            }
 
            // Erase all visited words.
            words.removeAll(visit);
            visit.clear();
        }
        return res;
    }
 
    // Driver Code
    public static void main(String[] args)
    {
        List<String> str
            = Arrays.asList("ted", "tex", "red", "tax",
                            "tad", "den", "rex", "pee");
        String beginWord = "red";
        String endWord = "tax";
 
        List<List<String> > res
            = findLadders(str, beginWord, endWord);
 
        displaypath(res);
    }
}


Python3




# Python Program to implement
# the above approach
from collections import deque
from typing import Deque, List, Set
 
# Function to print all possible shortest
# sequences starting from start to target.
def displaypath(res: List[List[str]]):
    for i in res:
        print("[ ", end="")
        for j in i:
            print(j, end=", ")
        print("]")
 
# Find words differing by a single
# character with word
def addWord(word: str, Dict: Set):
    res: List[str] = []
    wrd = list(word)
     
    # Find next word in dict by changing
    # each element from 'a' to 'z'
    for i in range(len(wrd)):
        s = wrd[i]
        c = 'a'
        while c <= 'z':
            wrd[i] = c
            if ''.join(wrd) in Dict:
                res.append(''.join(wrd))
            c = chr(ord(c) + 1)
        wrd[i] = s
    return res
 
# Function to get all the shortest possible
# sequences starting from 'start' to 'target'
def findLadders(Dictt: List[str], beginWord: str, endWord: str):
 
    # Store all the shortest path.
    res: List[List[str]] = []
 
    # Store visited words in list
    visit = set()
 
    # Queue used to find the shortest path
    q: Deque[List[str]] = deque()
 
    # Stores the distinct words from given list
    Dict = set()
    for i in Dictt:
        Dict.add(i)
    q.append([beginWord])
 
    # Stores whether the shortest
    # path is found or not
    flag = False
    while q:
        size = len(q)
        for i in range(size):
 
            # Explore the next level
            cur = q[0]
            q.popleft()
            newadd = []
 
            # Find words differing by a
            # single character
            newadd = addWord(cur[-1], Dict)
 
            # Add words to the path.
            for j in range(len(newadd)):
                newline = cur.copy()
                newline.append(newadd[j])
 
                # Found the target
                if (newadd[j] == endWord):
                    flag = True
                    res.append(newline)
 
                visit.add(newadd[j])
                q.append(newline)
 
        # If already reached target
        if (flag):
            break
 
        # Erase all visited words.
        for it in visit:
            Dict.remove(it)
        visit.clear()
    return res
 
# Driver Code
if __name__ == "__main__":
 
    string = ["ted", "tex", "red", "tax", "tad", "den", "rex", "pee"]
    beginWord = "red"
    endWord = "tax"
 
    res = findLadders(string, beginWord, endWord)
 
    displaypath(res)
 
# This code is contributed by sanjeev2552


C#




using System;
using System.Collections.Generic;
 
class Program
{
 
  // Function to print all possible shortest
  // sequences starting from start to target.
  static void DisplayPath(List<List<string> > res)
  {
    foreach(var item in res)
    {
      Console.Write("[ ");
      foreach(var word in item)
      {
        Console.Write(word + ", ");
      }
      Console.Write(" ]\n");
    }
  }
 
  // Find words differing by a single
  // character with word
  static List<string> AddWord(string word,
                              HashSet<string> dict)
  {
    var res = new List<string>();
 
    // Find next word in dict by changing
    // each element from 'a' to 'z'
    for (int i = 0; i < word.Length; i++) {
      char s = word[i];
      for (char c = 'a'; c <= 'z'; c++) {
        word = word.Remove(i, 1).Insert(
          i, c.ToString());
        if (dict.Contains(word))
          res.Add(word);
      }
      word
        = word.Remove(i, 1).Insert(i, s.ToString());
    }
    return res;
  }
 
  // Function to get all the shortest possible
  // sequences starting from 'start' to 'target'
  static List<List<string> >
    FindLadders(List<string> Dict, string beginWord,
                string endWord)
  {
    // Store all the shortest path.
    var res = new List<List<string> >();
 
    // Store visited words in list
    var visit = new HashSet<string>();
 
    // Queue used to find the shortest path
    var q = new Queue<List<string> >();
    q.Enqueue(new List<string>{ beginWord });
 
    // Stores the distinct words from given list
    var dict = new HashSet<string>(Dict);
 
    // Stores whether the shortest
    // path is found or not
    bool flag = false;
 
    while (q.Count > 0) {
      int size = q.Count;
      for (int i = 0; i < size; i++) {
        // Explore the next level
        List<string> cur = q.Dequeue();
        var newadd
          = AddWord(cur[cur.Count - 1], dict);
 
        // Add words to the path.
        foreach(var word in newadd)
        {
          var newline = new List<string>(cur);
 
          newline.Add(word);
 
          // Found the target
          if (word == endWord) {
            flag = true;
            res.Add(newline);
          }
 
          visit.Add(word);
          q.Enqueue(newline);
        }
      }
 
      // If already reached target
      if (flag) {
        break;
      }
 
      // Erase all visited words.
      foreach(var item in visit)
      {
        dict.Remove(item);
      }
 
      visit.Clear();
    }
    return res;
  }
 
  // Driver Code
  static void Main(string[] args)
  {
    var str = new List<string>{ "ted", "tex", "red",
                               "tax", "tad", "den",
                               "rex", "pee" };
    var beginWord = "red";
    var endWord = "tax";
 
    var res = FindLadders(str, beginWord, endWord);
 
    DisplayPath(res);
  }
}


Javascript




//  JavaScript Program to implement
 
  // Find words differing by a single
  // character with word
function addWord(word, dict) {
  const res = [];
 
  // Find next word in dict by changing
  // each element from 'a' to 'z'
  for (let i = 0; i < word.length; i++) {
    const s = word[i];
    for (let c = 97; c <= 122; c++) {
      word = word.substr(0, i) + String.fromCharCode(c) + word.substr(i + 1);
      if (dict.has(word)) {
        res.push(word);
      }
    }
    word = word.substr(0, i) + s + word.substr(i + 1);
  }
  return res;
}
 // Function to get all the shortest possible
  // sequences starting from 'start' to 'target'
 
function findLadders(dict, beginWord, endWord) {
  // Store all the shortest path.
  const res = [];
 
  // Store visited words in set.
  const visit = new Set();
 
  // Queue used to find the shortest path
  const q = [ [beginWord] ];
 
  // Stores the distinct words from given list
  const dictSet = new Set(dict);
 
  // Stores whether the shortest path is found or not
  let flag = false;
 
  while (q.length > 0) {
    const size = q.length;
    for (let i = 0; i < size; i++) {
      // Explore the next level
      const cur = q.shift();
      const newAdd = addWord(cur[cur.length - 1], dictSet);
 
      // Add words to the path
      for (const word of newAdd) {
        const newLine = [...cur, word];
 
        // Found the target
        if (word === endWord) {
          flag = true;
          res.push(newLine);
        }
 
        visit.add(word);
        q.push(newLine);
      }
    }
 
    // If already reached target
    if (flag) {
      break;
    }
 
    // Erase all visited words
    for (const item of visit) {
      dictSet.delete(item);
    }
 
    visit.clear();
  }
 
  return res;
}
 
function displayPath(res) {
  for (const item of res) {
    process.stdout.write("[ ");
    for (const word of item) {
      process.stdout.write(word + ", ");
    }
    process.stdout.write(" ]\n");
  }
}
 
// Driver code
const dict = ["ted", "tex", "red", "tax", "tad", "den", "rex", "pee"];
const beginWord = "red";
const endWord = "tax";
 
const res = findLadders(dict, beginWord, endWord);
displayPath(res);
 
// This code is contributed by rutikbhosale


Output: 

[ red, ted, tad, tax,  ]
[ red, ted, tex, tax,  ]
[ red, rex, tex, tax,  ]

 

Time complexity: O(N²*M), where M is the number of strings in the given list and N is the length of each string.

Auxiliary Space:O(M*N)



Last Updated : 06 Mar, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads