Given a dictionary, and two words ‘start’ and ‘target’ (both of 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 dictionary and length of all dictionary words is same.
Example:
Input: Dictionary = {POON, PLEE, SAME, POIE, PLEA, PLIE, POIN}, start = TOON, target = PLEA
Output: 7
Explanation: TOON – POON – POIN – POIE – PLIE – PLEE – PLEA
Input: Dictionary = {ABCD, EBAD, EBCD, XYZA}, start = ABCV, target = EBAD
Output: 4
Explanation: ABCV – ABCD – EBCD – EBAD
Approach: The idea to solve the problem is to use BFS. To find the shortest path through BFS, start from the start word and push it in a queue. And once the target is found for the first time, then return that level of BFS traversal. In each step of BFS one can get all the words that can be formed using that many steps. So whenever the target word is found for the first time that will be the length of the shortest chain of words.
- Start from the given start word.
- Push the word in the queue
- Run a loop until the queue is empty
- Traverse all words that adjacent (differ by one character) to it and push the word in a queue (for BFS)
- Keep doing so until we find the target word or we have traversed all words.
Below are the implementations of the above idea.
C++
#include <bits/stdc++.h>
using namespace std;
int shortestChainLen(
string start, string target,
set<string>& D)
{
if (start == target)
return 0;
if (D.find(target) == D.end())
return 0;
int level = 0, wordlength = start.size();
queue<string> Q;
Q.push(start);
while (!Q.empty()) {
++level;
int sizeofQ = Q.size();
for ( int i = 0; i < sizeofQ; ++i) {
string word = Q.front();
Q.pop();
for ( int pos = 0; pos < wordlength; ++pos) {
char orig_char = word[pos];
for ( char c = 'a' ; c <= 'z' ; ++c) {
word[pos] = c;
if (word == target)
return level + 1;
if (D.find(word) == D.end())
continue ;
D.erase(word);
Q.push(word);
}
word[pos] = orig_char;
}
}
}
return 0;
}
int main()
{
set<string> D;
D.insert( "poon" );
D.insert( "plee" );
D.insert( "same" );
D.insert( "poie" );
D.insert( "plie" );
D.insert( "poin" );
D.insert( "plea" );
string start = "toon" ;
string target = "plea" ;
cout << "Length of shortest chain is: "
<< shortestChainLen(start, target, D);
return 0;
}
|
Java
import java.util.*;
class GFG
{
static int shortestChainLen(String start,
String target,
Set<String> D)
{
if (start == target)
return 0 ;
if (!D.contains(target))
return 0 ;
int level = 0 , wordlength = start.length();
Queue<String> Q = new LinkedList<>();
Q.add(start);
while (!Q.isEmpty())
{
++level;
int sizeofQ = Q.size();
for ( int i = 0 ; i < sizeofQ; ++i)
{
char []word = Q.peek().toCharArray();
Q.remove();
for ( int pos = 0 ; pos < wordlength; ++pos)
{
char orig_char = word[pos];
for ( char c = 'a' ; c <= 'z' ; ++c)
{
word[pos] = c;
if (String.valueOf(word).equals(target))
return level + 1 ;
if (!D.contains(String.valueOf(word)))
continue ;
D.remove(String.valueOf(word));
Q.add(String.valueOf(word));
}
word[pos] = orig_char;
}
}
}
return 0 ;
}
public static void main(String[] args)
{
Set<String> D = new HashSet<String>();
D.add( "poon" );
D.add( "plee" );
D.add( "same" );
D.add( "poie" );
D.add( "plie" );
D.add( "poin" );
D.add( "plea" );
String start = "toon" ;
String target = "plea" ;
System.out.print( "Length of shortest chain is: "
+ shortestChainLen(start, target, D));
}
}
|
Python3
from collections import deque
def shortestChainLen(start, target, D):
if start = = target:
return 0
if target not in D:
return 0
level, wordlength = 0 , len (start)
Q = deque()
Q.append(start)
while ( len (Q) > 0 ):
level + = 1
sizeofQ = len (Q)
for i in range (sizeofQ):
word = [j for j in Q.popleft()]
for pos in range (wordlength):
orig_char = word[pos]
for c in range ( ord ( 'a' ), ord ( 'z' ) + 1 ):
word[pos] = chr (c)
if ("".join(word) = = target):
return level + 1
if ("".join(word) not in D):
continue
del D["".join(word)]
Q.append("".join(word))
word[pos] = orig_char
return 0
if __name__ = = '__main__' :
D = {}
D[ "poon" ] = 1
D[ "plee" ] = 1
D[ "same" ] = 1
D[ "poie" ] = 1
D[ "plie" ] = 1
D[ "poin" ] = 1
D[ "plea" ] = 1
start = "toon"
target = "plea"
print ( "Length of shortest chain is: " ,
shortestChainLen(start, target, D))
|
C#
using System;
using System.Collections.Generic;
class GFG
{
static int shortestChainLen(String start,
String target,
HashSet<String> D)
{
if (start == target)
return 0;
if (!D.Contains(target))
return 0;
int level = 0, wordlength = start.Length;
List<String> Q = new List<String>();
Q.Add(start);
while (Q.Count != 0)
{
++level;
int sizeofQ = Q.Count;
for ( int i = 0; i < sizeofQ; ++i)
{
char []word = Q[0].ToCharArray();
Q.RemoveAt(0);
for ( int pos = 0; pos < wordlength; ++pos)
{
char orig_char = word[pos];
for ( char c = 'a' ; c <= 'z' ; ++c)
{
word[pos] = c;
if (String.Join( "" , word).Equals(target))
return level + 1;
if (!D.Contains(String.Join( "" , word)))
continue ;
D.Remove(String.Join( "" , word));
Q.Add(String.Join( "" , word));
}
word[pos] = orig_char;
}
}
}
return 0;
}
public static void Main(String[] args)
{
HashSet<String> D = new HashSet<String>();
D.Add( "poon" );
D.Add( "plee" );
D.Add( "same" );
D.Add( "poie" );
D.Add( "plie" );
D.Add( "poin" );
D.Add( "plea" );
String start = "toon" ;
String target = "plea" ;
Console.Write( "Length of shortest chain is: "
+ shortestChainLen(start, target, D));
}
}
|
Javascript
<script>
function shortestChainLen(start,target,D)
{
if (start == target)
return 0;
if (!D.has(target))
return 0;
let level = 0, wordlength = start.length;
let Q = [];
Q.push(start);
while (Q.length != 0)
{
++level;
let sizeofQ = Q.length;
for (let i = 0; i < sizeofQ; ++i)
{
let word = Q[0].split( "" );
Q.shift();
for (let pos = 0; pos < wordlength; ++pos)
{
let orig_char = word[pos];
for (let c = 'a' .charCodeAt(0); c <= 'z' .charCodeAt(0); ++c)
{
word[pos] = String.fromCharCode(c);
if (word.join( "" ) == target)
return level + 1;
if (!D.has(word.join( "" )))
continue ;
D. delete (word.join( "" ));
Q.push(word.join( "" ));
}
word[pos] = orig_char;
}
}
}
return 0;
}
let D = new Set();
D.add( "poon" );
D.add( "plee" );
D.add( "same" );
D.add( "poie" );
D.add( "plie" );
D.add( "poin" );
D.add( "plea" );
let start = "toon" ;
let target = "plea" ;
document.write( "Length of shortest chain is: "
+ shortestChainLen(start, target, D));
</script>
|
Output
Length of shortest chain is: 7
Time Complexity: O(N² * M), where N is the number of entries originally in the dictionary and M is the size of the string.
Auxiliary Space: O(M * N)
Alternate Implementation: (Maintaining the mapping of the intermediate words and the original word):
Below is an alternative implementation to the above approach.
Here, in this approach, we find out all the intermediate words of the start word and the words in the given list of dictionary and maintain a map of the intermediate word and a vector of the original word (map<string, vector<string>>). For instance, for the word “POON”, the intermediate words are “*OON” , “P*ON”, “PO*N”, “POO*”. Then, we perform BFS traversal starting with the start word and push a pair of start word and the distance (pair(word, distance)) to the queue until we reach the target word. Then, the distance is our answer.
C++
#include <bits/stdc++.h>
using namespace std;
int shortestChainLen(
string start, string target,
set<string>& D)
{
if (start == target)
return 0;
map<string, vector<string>> umap;
for ( int i = 0; i < start.size(); i++)
{
string str = start.substr(0,i) + "*" +
start.substr(i+1);
umap[str].push_back(start);
}
for ( auto it = D.begin(); it != D.end(); it++)
{
string word = *it;
for ( int j = 0; j < word.size(); j++)
{
string str = word.substr(0,j) + "*" +
word.substr(j+1);
umap[str].push_back(word);
}
}
queue<pair<string, int >> q;
map<string, int > visited;
q.push(make_pair(start,1));
visited[start] = 1;
while (!q.empty())
{
pair<string, int > p = q.front();
q.pop();
string word = p.first;
int dist = p.second;
if (word == target)
{
return dist;
}
for ( int i = 0; i < word.size(); i++)
{
string str = word.substr(0,i) + "*" +
word.substr(i+1);
vector<string> vect = umap[str];
for ( int j = 0; j < vect.size(); j++)
{
if (visited[vect[j]] == 0)
{
visited[vect[j]] = 1;
q.push(make_pair(vect[j], dist + 1));
}
}
}
}
return 0;
}
int main()
{
set<string> D;
D.insert( "poon" );
D.insert( "plee" );
D.insert( "same" );
D.insert( "poie" );
D.insert( "plie" );
D.insert( "poin" );
D.insert( "plea" );
string start = "toon" ;
string target = "plea" ;
cout << "Length of shortest chain is: "
<< shortestChainLen(start, target, D);
return 0;
}
|
Java
import java.util.*;
public class GFG{
static class pair
{
String first;
int second;
public pair(String first, int second)
{
this .first = first;
this .second = second;
}
}
static int shortestChainLen(
String start, String target,
HashSet<String> D)
{
if (start == target)
return 0 ;
Map<String, Vector<String>> umap = new HashMap<>();
for ( int i = 0 ; i < start.length(); i++)
{
String str = start.substring( 0 ,i) + "*" +
start.substring(i+ 1 );
Vector<String> s = umap.get(str);
if (s== null )
s = new Vector<String>();
s.add(start);
umap.put(str, s);
}
for (String it : D)
{
String word = it;
for ( int j = 0 ; j < word.length(); j++)
{
String str = word.substring( 0 , j) + "*" +
word.substring(j + 1 );
Vector<String> s = umap.get(str);
if (s == null )
s = new Vector<String>();
s.add(word);
umap.put(str, s);
}
}
Queue<pair> q = new LinkedList<>();
Map<String, Integer> visited = new HashMap<String, Integer>();
q.add( new pair(start, 1 ));
visited.put(start, 1 );
while (!q.isEmpty())
{
pair p = q.peek();
q.remove();
String word = p.first;
int dist = p.second;
if (word == target)
{
return dist;
}
for ( int i = 0 ; i < word.length(); i++)
{
String str = word.substring( 0 , i) + "*" +
word.substring(i + 1 );
Vector<String> vect = umap.get(str);
for ( int j = 0 ; j < vect.size(); j++)
{
if (!visited.containsKey(vect.get(j)) )
{
visited.put(vect.get(j), 1 );
q.add( new pair(vect.get(j), dist + 1 ));
}
}
}
}
return 0 ;
}
public static void main(String[] args)
{
HashSet<String> D = new HashSet<String>();
D.add( "poon" );
D.add( "plee" );
D.add( "same" );
D.add( "poie" );
D.add( "plie" );
D.add( "poin" );
D.add( "plea" );
String start = "toon" ;
String target = "plea" ;
System.out.print( "Length of shortest chain is: "
+ shortestChainLen(start, target, D));
}
}
|
Python3
from typing import List , Tuple , Set , Dict , Any , Union
def shortest_chain_len(start: str , target: str , D: Set [ str ]) - > int :
if start = = target:
return 0
umap: Dict [ str , List [ str ]] = {}
for i in range ( len (start)):
intermediate_word = start[:i] + "*" + start[i + 1 :]
umap[intermediate_word] = []
for word in D:
for i in range ( len (word)):
intermediate_word = word[:i] + "*" + word[i + 1 :]
if intermediate_word not in umap:
umap[intermediate_word] = []
umap[intermediate_word].append(word)
q = [(start, 1 )]
visited = {start: 1 }
while q:
word, dist = q.pop( 0 )
if word = = target:
return dist
for i in range ( len (word)):
intermediate_word = word[:i] + '*' + word[i + 1 :]
vect = umap[intermediate_word]
for k in range ( len (vect)):
if vect[k] not in visited:
visited[vect[k]] = 1
q.append((vect[k], dist + 1 ))
return 0
D = { 'poon' , 'plee' , 'same' , 'poie' , 'plie' , 'poin' , 'plea' }
start = "toon"
target = "plea"
print (f "Length of shortest chain is: {shortest_chain_len(start, target, D)}" )
|
C#
using System;
using System.Collections.Generic;
using System.Linq;
namespace GFG {
public class GFG {
class pair {
public string first;
public int second;
public pair( string first, int second)
{
this .first = first;
this .second = second;
}
}
static int shortestChainLen( string start, string target,
HashSet< string > D)
{
if (start == target)
return 0;
Dictionary< string , List< string > > umap
= new Dictionary< string , List< string > >();
for ( int i = 0; i < start.Length; i++) {
string str = start.Substring(0, i) + "*"
+ start.Substring(i + 1);
if (!umap.ContainsKey(str))
umap[str] = new List< string >();
umap[str].Add(start);
}
foreach ( string it in D)
{
string word = it;
for ( int j = 0; j < word.Length; j++) {
string str = word.Substring(0, j) + "*"
+ word.Substring(j + 1);
if (!umap.ContainsKey(str))
umap[str] = new List< string >();
umap[str].Add(word);
}
}
Queue<pair> q = new Queue<pair>();
Dictionary< string , int > visited
= new Dictionary< string , int >();
q.Enqueue( new pair(start, 1));
visited[start] = 1;
while (q.Count != 0) {
pair p = q.Peek();
q.Dequeue();
string word = p.first;
int dist = p.second;
if (word == target) {
return dist;
}
for ( int i = 0; i < word.Length; i++) {
string str = word.Substring(0, i) + "*"
+ word.Substring(i + 1);
List< string > vect
= umap.ContainsKey(str)
? umap[str]
: new List< string >();
foreach ( string s in vect)
{
if (!visited.ContainsKey(s)) {
visited[s] = 1;
q.Enqueue( new pair(s, dist + 1));
}
}
}
}
return 0;
}
public static void Main( string [] args)
{
HashSet< string > D = new HashSet< string >() {
"poon" , "plee" , "same" , "poie" , "plie" , "poin" ,
"plea"
};
string start = "toon" ;
string target = "plea" ;
Console.WriteLine(
"Length of shortest chain is: "
+ shortestChainLen(start, target, D));
}
}
}
|
Javascript
class Queue {
constructor() {
this .items = [];
}
push(element) {
return this .items.push(element);
}
pop() {
if ( this .items.length > 0) {
return this .items.shift();
}
}
front() {
return this .items[0];
}
empty() {
return this .items.length == 0;
}
size() {
return this .items.length;
}
clear() {
this .items = [];
}
}
function shortestChainLen(start, target, D) {
if (start == target) {
return 0;
}
let umap = new Map();
for (let i = 0; i < start.length; i++) {
let str = start.slice(0, i) + "*" + start.slice(i + 1);
if (umap.get(str) === undefined) {
umap.set(str, [start]);
} else {
let brr = umap.get(str);
brr.push(start);
umap.set(str, brr);
}
}
for (it of D.values()) {
let word = it;
for (let j = 0; j < word.length; j++) {
let str = word.slice(0, j) + "*" + word.slice(j + 1);
if (umap.get(str) === undefined) {
umap.set(str, [word]);
} else {
let arr = umap.get(str);
arr.push(word);
umap.set(str, arr);
}
}
}
let q = new Queue();
let visited = new Map();
q.push([start, 1]);
visited.set(start, 1);
while (!q.empty()) {
let p = q.front();
q.pop();
let word = p[0];
let dist = p[1];
if (word == target) {
return dist;
}
for (let i = 0; i < word.length; i++) {
let str = word.slice(0, i) + "*" + word.slice(i + 1);
let vect = umap.get(str);
for (let j = 0; j < vect.length; j++) {
if (visited.get(vect[j]) === undefined) {
visited.set(vect[j], 1);
q.push([vect[j], dist + 1]);
}
}
}
}
return 0;
}
let D = new Set();
D.add( "poon" );
D.add( "plee" );
D.add( "same" );
D.add( "poie" );
D.add( "plie" );
D.add( "poin" );
D.add( "plea" );
let start = "toon" ;
let target = "plea" ;
console.log(
"Length of shortest chain is: " + shortestChainLen(start, target, D)
);
|
Output
Length of shortest chain is: 7
Time Complexity: O(N² * M), where N is the number of entries originally in the dictionary and M is the size of the string.
Auxiliary Space: O(M * N)
Feeling lost in the world of random DSA topics, wasting time without progress? It's time for a change! Join our DSA course, where we'll guide you on an exciting journey to master DSA efficiently and on schedule.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 geeks!