Given a starting string X of 3 characters, finishing string Y of 3 characters and an array of forbidden strings. The task is to find the minimum number of clicks to reach Y from X.
Rules:
- Each of the 3 characters changes in a circular manner i.e. on each click you can go from either a to b or a to z and none of the forbidden words is ever displayed.
- If it is not possible to reach Y, print -1. In each click, only a single letter can be changed.
- Each forbidden string is of the form: {“S1” “S2” “S3”} where each string Si contains forbidden letters for that character.
- Forbidden string = {“ac” “bx” “lw”} implies words “abl”, “cxw”, “cbl”, “abw”, “cbw”, “axl”, “axw” and “cxl” are forbidden and will never be displayed.
Note: If the starting string X is also a possible combination of forbidden characters, then also the result should be -1.
Input: X = “znw”, Y = “lof”, N = 4 (no of forbidden strings)
forbidden =
{ ” qlb “, ” jcm “, ” mhoq ” },
{ ” azn “, ” piy “, ” vj ” },
{ ” by “, ” oy “, ” ubo ” },
{ ” jqm “, ” f “, ” ej ” }
Output: Minimum no of clicks required is 22
Explanation: Since no combination out of the given forbidden strings forms the final string Y, so the string Y becomes valid.Thus minimum number of clicks required is computed as:
z – l in forward direction by 12 clicks
z – l in backward direction by 14 clicks
n – o in forward direction by 1 click
n – o in backward direction by 25 clicks
w – f in forward direction by 9 clicks
w – f in backward direction by 17 clicksTotal minimum clicks = 12 + 1 + 9 = 22.
Input: X = “bdb”, Y = “xxx”, N = 1 (no of forbidden strings)
forbidden = { ” ax “, ” acx “, ” bxy ” }
Output: Minimum no of clicks required is -1
Explanation: As “xxx” is a possible combination of forbidden characters, therefore it is not possible to reach Y from X.
Approach:
Use BFS(Breadth First Search) with certain modifications in order to get the min number of clicks, bypassing the forbidden strings.
- Since each of the 3 positions can contain alphabets, hence create a 3D visited array of dimensions 26 * 26 * 26 in order to traverse the word states.
- To visualize each of the restricted words, create another 3D array of dimensions 26 * 26 * 26 to keep track of the words which must never be visited in the traversal.
- Since each of the 3 characters changes in a circular manner i.e, letters will change in a circular fashion on each click, there is a need to take care to modulo 26 every time the next letter is reached.
- Let current state of word be [X Y Z]. Then on a single click movement, the 6 states are possible.
- Hence create 3 utility arrays dx, dy, dz to keep the traversal a streamlined process. Store each word state in a struct having 4 fields namely a, b, c (each of the 3 characters) and distance from the starting words.
- The six stare are following:
[ X+1 Y Z ], [ X-1 Y Z ], [ X Y+1 Z ], [ X Y-1 Z ], [ X Y Z+1 ], [ X Y Z-1 ].
Below is the implementation of above approach:
// C++ code for above program. #include <bits/stdc++.h> 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<vector<string> >& 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<node> 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<vector<string> > forbidden
= { { "qlb" , "jcm" , "mhoq" },
{ "azn" , "piy" , "vj" },
{ "by" , "oy" , "ubo" },
{ "jqm" , "f" , "ej" } };
solve(X, Y, N, forbidden);
return 0;
} |
// Java code addition import java.io.*;
import java.util.*;
public class GFG {
// each node represents a word state
static class Node {
int a, b, c;
// dist from starting word X
int dist;
public Node( int a, int b, int c, int dist) {
this .a = a;
this .b = b;
this .c = c;
this .dist = dist;
}
}
// 3D visited array
static boolean [][][] visited = new boolean [ 26 ][ 26 ][ 26 ];
// 3D restricted array
static boolean [][][] restricted = new boolean [ 26 ][ 26 ][ 26 ];
// utility arrays for single step
// traversal in left and right
static int [] dx = { 1 , - 1 , 0 , 0 , 0 , 0 };
static int [] dy = { 0 , 0 , 1 , - 1 , 0 , 0 };
static int [] dz = { 0 , 0 , 0 , 0 , 1 , - 1 };
// function to find the minimum clicks.
public static void solve(String start, String end, int qx,
final ArrayList<ArrayList<String>> forbidden) {
Arrays.fill(visited[ 0 ][ 0 ], false );
Arrays.fill(restricted[ 0 ][ 0 ], false );
for (ArrayList<String> vec : forbidden) {
String a = vec.get( 0 );
String b = vec.get( 1 );
String c = vec.get( 2 );
for ( char x : a.toCharArray())
for ( char y : b.toCharArray())
for ( char z : c.toCharArray()) {
// 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.charAt( 0 ) - 'a' ;
int ea = end.charAt( 0 ) - 'a' ;
// starting and ending letter b
int sb = start.charAt( 1 ) - 'a' ;
int eb = end.charAt( 1 ) - 'a' ;
// starting and ending letter c
int sc = start.charAt( 2 ) - 'a' ;
int ec = end.charAt( 2 ) - 'a' ;
if (restricted[sa][sb][sc]
|| restricted[ea][eb][ec]) {
// check if starting word
// or finishing word is
// restricted or not
System.out.println(- 1 );
return ;
}
// queue of nodes for BFS
Queue<Node> q = new LinkedList<Node>();
// initial starting word pushed in
// queue. dist = 0 for starting word
q.add( new Node(sa, sb, sc, 0 ));
// mark as visited
visited[sa][sb][sc] = true ;
while (!q.isEmpty()) {
Node x = q.poll();
// final destination reached condition
if (x.a == (end.charAt( 0 ) - 'a' )
&& x.b == (end.charAt( 1 ) - 'a' )
&& x.c == (end.charAt( 2 ) - 'a' )) {
System.out.println(x.dist);
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]
&& !visited[A][B][C]) {
// if a valid word state,
// push into queue
q.add( new Node(A, B, C, DIST + 1 ));
visited[A][B][C] = true ;
}
}
}
// reach here if not possible
// to reach final word Y
System.out.println(- 1 );
}
// Driver Code
public static void main(String[] args)
{
// starting string
String X = "znw" ;
// final string
String Y = "lof" ;
// no of restricting word vectors
int N = 4 ;
ArrayList<ArrayList<String>> forbidden = new ArrayList<ArrayList<String>>( 3 );
// Adding elements to the 2D ArrayList
forbidden.add( new ArrayList<String>(Arrays.asList( "qlb" , "jcm" , "mhoq" )));
forbidden.add( new ArrayList<String>(Arrays.asList( "azn" , "piy" , "vj" )));
forbidden.add( new ArrayList<String>(Arrays.asList( "by" , "oy" , "ubo" )));
forbidden.add( new ArrayList<String>(Arrays.asList( "jqm" , "f" , "ej" )));
solve(X, Y, N, forbidden);
}
} // The code is contributed by Arushi Goel. |
# Python code for above program. from collections import deque
dx = [ 1 , - 1 , 0 , 0 , 0 , 0 ]
dy = [ 0 , 0 , 1 , - 1 , 0 , 0 ]
dz = [ 0 , 0 , 0 , 0 , 1 , - 1 ]
# each node represents a word state class Node:
def __init__( self , a, b, c, dist):
self .a = a
self .b = b
self .c = c
# dist from starting word X
self .dist = dist
# function to find the # minimum clicks. def solve(start, end, qx, forbidden):
visited = [[[ False for _ in range ( 26 )]
for _ in range ( 26 )]
for _ in range ( 26 )]
restricted = [[[ False for _ in range ( 26 )]
for _ in range ( 26 )]
for _ in range ( 26 )]
for a, b, c in forbidden:
for x in a:
for y in b:
for z in c:
# each invalid word is
# decoded and marked as
# restricted = true.
restricted[ ord (x) - ord ( 'a' )][ ord (y) -
ord ( 'a' )][ ord (z) - ord ( 'a' )] = True
# starting and ending letter a
sa, ea = ord (start[ 0 ]) - ord ( 'a' ), ord (end[ 0 ]) - ord ( 'a' )
# starting and ending letter b
sb, eb = ord (start[ 1 ]) - ord ( 'a' ), ord (end[ 1 ]) - ord ( 'a' )
# starting and ending letter c
sc, ec = ord (start[ 2 ]) - ord ( 'a' ), ord (end[ 2 ]) - ord ( 'a' )
if restricted[sa][sb][sc] or restricted[ea][eb][ec]:
# check if starting word
# or finishing word is
# restricted or not
print ( - 1 )
return
q = deque()
# initial starting word pushed in
# queue. dist = 0 for starting word
q.append(Node(sa, sb, sc, 0 ))
# mark as visited
visited[sa][sb][sc] = True
while q:
x = q.popleft()
# final destination reached condition
if x.a = = ea and x.b = = eb and x.c = = ec:
print (x.dist)
return
DIST = x.dist
for i in range ( 6 ):
# mod 26 for circular letter sequence
# next letter for a
A = (x.a + dx[i] + 26 ) % 26
# next letter for b
B = (x.b + dy[i] + 26 ) % 26
# next letter for c
C = (x.c + dz[i] + 26 ) % 26
if not restricted[A][B][C] and not visited[A][B][C]:
# if a valid word state,
# push into queue
q.append(Node(A, B, C, DIST + 1 ))
visited[A][B][C] = True
# reach here if not possible
# to reach final word Y
print ( - 1 )
# Driver Code # starting string X = "znw"
# final string Y = "lof"
# no of restricting word vectors N = 4
forbidden = [[ "qlb" , "jcm" , "mhoq" ], [ "azn" , "piy" , "vj" ], [ "by" , "oy" , "ubo" ], [ "jqm" , "f" , "ej" ]]
solve(X, Y, N, forbidden) |
// C#// each node represents a word state code for above program. using System;
using System.Collections.Generic;
// each node represents a word state public struct Node
{ public int a, b, c;
// dist from starting word X
public int dist;
} public class Program
{ public static void Solve( string start, string end, int N, List<List< string >> forbidden)
{
// 3D visited array
bool [,,] visited = new bool [26,26,26];
// 3D restricted array
bool [,,] restricted = new bool [26,26,26];
foreach (List< string > vec in forbidden)
{
string a = vec[0];
string b = vec[1];
string c = vec[2];
foreach ( char x in a)
{
foreach ( char y in b)
{
foreach ( char z in c)
{
// each invalid word is
// decoded and marked as
// restricted = true. // starting and ending letter a
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] || restricted[ea, eb, ec])
{
// check if starting word
// or finishing word is
// restricted or not
Console.WriteLine( "-1" );
return ;
}
// queue of nodes for BFS
Queue<Node> q = new Queue<Node>();
// initial starting word pushed in
// queue. dist = 0 for starting word
q.Enqueue( new Node { a = sa, b = sb, c = sc, dist = 0 });
// mark as visited
visited[sa, sb, sc] = true ;
while (q.Count > 0)
{
Node x = q.Dequeue();
// final destination reached condition
if (x.a == ea && x.b == eb && x.c == ec)
{
Console.WriteLine(x.dist);
return ;
}
int DIST = x.dist;
// utility arrays for single step
// traversal in left and right int [] dx = { 1, -1, 0, 0, 0, 0 };
int [] dy = { 0, 0, 1, -1, 0, 0 };
int [] dz = { 0, 0, 0, 0, 1, -1 };
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] && !visited[A, B, C])
{
q.Enqueue( new Node { a = A, b = B, c = C, dist = DIST + 1 });
visited[A, B, C] = true ;
}
}
}
// reach here if not possible
// to reach final word Y
Console.WriteLine( "-1" );
}
// Driver Code public static void Main()
{
// starting string
string X = "znw" ;
// final string
string Y = "lof" ;
// no of restricting word vectors
int N = 4;
List<List< string >> forbidden = new List<List< string >>
{
new List< string >{ "qlb" , "jcm" , "mhoq" },
new List< string >{ "azn" , "piy" , "vj" },
new List< string >{ "by" , "oy" , "ubo" },
new List< string >{ "jqm" , "f" , "ej" }
};
Solve(X, Y, N, forbidden);
}
} |
// JavaScript code for above program. const dx = [1, -1, 0, 0, 0, 0]; const dy = [0, 0, 1, -1, 0, 0]; const dz = [0, 0, 0, 0, 1, -1]; // each node represents a word state class Node { constructor(a, b, c, dist) {
this .a = a;
this .b = b;
this .c = c;
// dist from starting word X
this .dist = dist;
}
} // function to find the minimum clicks. function solve(start, end, forbidden) {
const visited = Array.from({ length: 26 }, () =>
Array.from({ length: 26 }, () => Array.from({ length: 26 }, () => false ))
);
const restricted = Array.from({ length: 26 }, () =>
Array.from({ length: 26 }, () => Array.from({ length: 26 }, () => false ))
);
for (const [a, b, c] of forbidden) {
for (const x of a) {
for (const y of b) {
for (const z of c) {
// each invalid word is
// decoded and marked as
// restricted = true.
restricted[x.charCodeAt() - 97][y.charCodeAt() - 97][
z.charCodeAt() - 97
] = true ;
}
}
}
}
// starting and ending letter a
const sa = start.charCodeAt(0) - 97;
const ea = end.charCodeAt(0) - 97;
// starting and ending letter b
const sb = start.charCodeAt(1) - 97;
const eb = end.charCodeAt(1) - 97;
// starting and ending letter c
const sc = start.charCodeAt(2) - 97;
const ec = end.charCodeAt(2) - 97;
if (restricted[sa][sb][sc] || restricted[ea][eb][ec]) {
// check if starting word or finishing word is restricted or not
console.log(-1);
return ;
}
const q = [];
// initial starting word pushed in queue. dist = 0 for starting word
q.push( new Node(sa, sb, sc, 0));
// mark as visited
visited[sa][sb][sc] = true ;
while (q.length > 0) {
const x = q.shift();
// final destination reached condition
if (x.a === ea && x.b === eb && x.c === ec) {
console.log(x.dist);
return ;
}
const DIST = x.dist;
for (let i = 0; i < 6; i++) {
// mod 26 for circular letter sequence
// next letter for a
const A = ((x.a + dx[i] + 26) % 26) | 0;
// next letter for b
const B = ((x.b + dy[i] + 26) % 26) | 0;
// next letter for c
const C = ((x.c + dz[i] + 26) % 26) | 0;
if (!restricted[A][B][C] && !visited[A][B][C]) {
// if a valid word state, push into queue
q.push( new Node(A, B, C, DIST + 1));
visited[A
][B][C] = true ;
}
}
}
// reach here if not possible to reach final word Y
console.log(-1);
} // Driver Code // starting string const X = "znw" ;
// final string const Y = "lof" ;
// no of restricting word vectors const N = 4; const forbidden = [ [ "qlb" , "jcm" , "mhoq" ],
[ "azn" , "piy" , "vj" ],
[ "by" , "oy" , "ubo" ],
[ "jqm" , "f" , "ej" ],
]; solve(X, Y, forbidden); |
22
Time Complexity: O(26 * 26 * 26), since at max, there can be 26*26*26 word states.
Space Complexity: O(26 * 26 * 26)