Given an array of words, find any alphabetical order in the English alphabet such that the given words can be considered sorted (increasing), if there exists such an order, otherwise output impossible.
Examples:
Input : words[] = {"zy", "ab"}
Output : zabcdefghijklmnopqrstuvwxy
Basically we need to make sure that 'z' comes
before 'a'.
Input : words[] = {"geeks", "gamers", "coders",
"everyoneelse"}
Output : zyxwvutsrqponmlkjihgceafdb
Input : words[] = {"marvel", "superman", "spiderman",
"batman"
Output : zyxwvuptrqonmsbdlkjihgfeca
Naive approach:
The brute-force approach would be to check all the possible orders, and check if any of them satisfy the given order of words. Considering there are 26 alphabets in the English language, there are 26! number of permutations that can be valid orders. Considering we check every pair for verifying an order, the complexity of this approach goes to O(26!*N^2), which is well beyond practically preferred time complexity. Using topological sort: This solution requires knowledge of Graphs and its representation as adjacency lists, DFS and Topological sorting.
In our required order, it is required to print letters such that each letter must be followed by the letters that are placed in lower priority than them. It seems somewhat similar to what topological sort is defined as – In topological sorting, we need to print a vertex before its adjacent vertices. Let’s define each letter in the alphabet as nodes in a standard directed graph. A is said to be connected to B (A—>B) if A precedes B in the order.
The algorithm can be formulated as follows:
- If n is 1, then any order is valid.
- Take the first two words. Identify the first different letter (at the same index of the words) in the words. The letter in the first word will precede the letter in the second word.
- If there exists no such letter, then the first string must be smaller in length than the second string.
- Assign the second word to the first word and input the third word into the second word. Repeat 2, 3 and 4 (n-1) times.
- Run a DFS traversal in topological order.
- Check if all the nodes are visited. In topological order, if there are cycles in the graph, the nodes in the cycles remain not visited, since it is not possible to visit these nodes after visiting every node adjacent to it. In such a case, order does not exist. In this case, it means that the order in our list contradicts itself.
Implementation:
C++
#include <bits/stdc++.h>
using namespace std;
#define MAX_CHAR 26
void findOrder(vector<string> v)
{
int n = v.size();
if (n == 1) {
cout << "abcdefghijklmnopqrstuvwxyz" ;
return ;
}
vector< int > adj[MAX_CHAR];
vector< int > in(MAX_CHAR, 0);
string prev = v[0];
for ( int i = 1; i < n; ++i) {
string s = v[i];
int j;
for (j = 0; j < min(prev.length(), s.length()); ++j)
if (s[j] != prev[j])
break ;
if (j < min(prev.length(), s.length())) {
adj[prev[j] - 'a' ].push_back(s[j] - 'a' );
in[s[j] - 'a' ]++;
prev = s;
continue ;
}
if (prev.length() > s.length()) {
cout << "Impossible" ;
return ;
}
prev = s;
}
stack< int > stk;
for ( int i = 0; i < MAX_CHAR; ++i)
if (in[i] == 0)
stk.push(i);
vector< char > out;
bool vis[26];
memset (vis, false , sizeof (vis));
while (!stk.empty()) {
char x = stk.top();
stk.pop();
vis[x] = true ;
out.push_back(x + 'a' );
for ( int i = 0; i < adj[x].size(); ++i) {
if (vis[adj[x][i]])
continue ;
in[adj[x][i]]--;
if (in[adj[x][i]] == 0)
stk.push(adj[x][i]);
}
}
for ( int i = 0; i < MAX_CHAR; ++i)
if (!vis[i]) {
cout << "Impossible" ;
return ;
}
for ( int i = 0; i < out.size(); ++i)
cout << out[i];
}
int main()
{
vector<string> v{ "efgh" , "abcd" };
findOrder(v);
return 0;
}
|
Java
import java.util.ArrayList;
import java.util.Stack;
public class Sorted {
@SuppressWarnings ( "unchecked" )
static void findOrder(String[] v)
{
int n = v.length;
int MAX_CHAR = 26 ;
if (n == 1 ) {
System.out.println(
"abcdefghijklmnopqrstuvwxyz" );
return ;
}
ArrayList<Integer>[] adj = new ArrayList[MAX_CHAR];
for ( int i = 0 ; i < MAX_CHAR; i++)
adj[i] = new ArrayList<Integer>();
int [] in = new int [MAX_CHAR];
String prev = v[ 0 ];
for ( int i = 1 ; i < n; ++i) {
String s = v[i];
int j;
for (j = 0 ;
j < Math.min(prev.length(), s.length());
++j)
if (s.charAt(j) != prev.charAt(j))
break ;
if (j < Math.min(prev.length(), s.length())) {
adj[prev.charAt(j) - 'a' ].add(s.charAt(j)
- 'a' );
in[s.charAt(j) - 'a' ]++;
prev = s;
continue ;
}
if (prev.length() > s.length()) {
System.out.println( "Impossible" );
return ;
}
prev = s;
}
Stack<Integer> stk = new Stack<Integer>();
for ( int i = 0 ; i < MAX_CHAR; ++i)
if (in[i] == 0 )
stk.push(i);
ArrayList<Character> out
= new ArrayList<Character>();
boolean [] vis = new boolean [ 26 ];
while (!stk.empty()) {
int x = stk.peek();
stk.pop();
vis[x] = true ;
out.add(( char )(( char )x + 'a' ));
for ( int i = 0 ; i < adj[x].size(); ++i) {
if (vis[adj[x].get(i)])
continue ;
in[adj[x].get(i)]--;
if (in[adj[x].get(i)] == 0 )
stk.push(adj[x].get(i));
}
}
for ( int i = 0 ; i < MAX_CHAR; ++i)
if (!vis[i]) {
System.out.println( "Impossible" );
return ;
}
for ( int i = 0 ; i < out.size(); ++i)
System.out.print(out.get(i));
}
public static void main(String[] args)
{
String[] v = { "efgh" , "abcd" };
findOrder(v);
}
}
|
Python3
MAX_CHAR = 26
def findOrder(v):
n = len (v)
if (n = = 1 ):
print ( "abcdefghijklmnopqrstuvwxyz" )
return
adj = [[] for i in range (MAX_CHAR)]
In = [ 0 for i in range (MAX_CHAR)]
prev = v[ 0 ]
for i in range ( 1 ,n):
s = v[i]
for j in range ( min ( len (prev), len (s))):
if (s[j] ! = prev[j]):
break
if (j < min ( len (prev), len (s))):
adj[ ord (prev[j]) - ord ( 'a' )].append( ord (s[j]) - ord ( 'a' ))
In[ ord (s[j]) - ord ( 'a' )] + = 1
prev = s
continue
if ( len (prev) > len (s)):
print ( "Impossible" )
return
prev = s
stk = []
for i in range (MAX_CHAR):
if (In[i] = = 0 ):
stk.append(i)
out = []
vis = [ False for i in range ( 26 )]
while ( len (stk) > 0 ):
x = stk.pop()
vis[x] = True
out.append( chr (x + ord ( 'a' )))
for i in range ( len (adj[x])):
if (vis[adj[x][i]]):
continue
In[adj[x][i]] - = 1
if (In[adj[x][i]] = = 0 ):
stk.append(adj[x][i])
for i in range (MAX_CHAR):
if (vis[i] = = 0 ):
print ( "Impossible" )
return
for i in range ( len (out)):
print (out[i],end = "")
v = [ "efgh" , "abcd" ]
findOrder(v)
|
C#
using System;
using System.Collections.Generic;
class Sorted {
static void FindOrder( string [] v)
{
int n = v.Length;
int MAX_CHAR = 26;
if (n == 1) {
Console.WriteLine( "abcdefghijklmnopqrstuvwxyz" );
return ;
}
List< int >[] adj = new List< int >[ MAX_CHAR ];
for ( int i = 0; i < MAX_CHAR; i++)
adj[i] = new List< int >();
int [] ino = new int [MAX_CHAR];
string prev = v[0];
for ( int i = 1; i < n; ++i) {
string s = v[i];
int j;
for (j = 0; j < Math.Min(prev.Length, s.Length);
++j)
if (s[j] != prev[j])
break ;
if (j < Math.Min(prev.Length, s.Length)) {
adj[prev[j] - 'a' ].Add(s[j] - 'a' );
ino[s[j] - 'a' ]++;
prev = s;
continue ;
}
if (prev.Length > s.Length) {
Console.WriteLine( "Impossible" );
return ;
}
prev = s;
}
Stack< int > stk = new Stack< int >();
for ( int i = 0; i < MAX_CHAR; ++i)
if (ino[i] == 0)
stk.Push(i);
List< char > outo = new List< char >();
bool [] vis = new bool [26];
while (stk.Count > 0) {
int x = stk.Peek();
stk.Pop();
vis[x] = true ;
outo.Add(( char )(( char )x + 'a' ));
for ( int i = 0; i < adj[x].Count; ++i) {
if (vis[adj[x][i]])
continue ;
ino[adj[x][i]]--;
if (ino[adj[x][i]] == 0)
stk.Push(adj[x][i]);
}
}
for ( int i = 0; i < MAX_CHAR; ++i)
if (!vis[i]) {
Console.WriteLine( "Impossible" );
return ;
}
foreach ( char c in outo) Console.Write(c);
}
static void Main( string [] args)
{
string [] v = { "efgh" , "abcd" };
FindOrder(v);
}
}
|
Javascript
<script>
const MAX_CHAR = 26
function findOrder(v)
{
let n = v.length;
if (n == 1) {
document.write( "abcdefghijklmnopqrstuvwxyz" );
return ;
}
let adj = new Array(MAX_CHAR).fill(0).map(()=>[]);
let In = new Array(MAX_CHAR).fill(0);
let prev = v[0];
for (let i = 1; i < n; ++i) {
let s = v[i];
let j;
for (j = 0; j < Math.min(prev.length, s.length); ++j)
if (s[j] != prev[j])
break ;
if (j < Math.min(prev.length, s.length)) {
adj[prev.charCodeAt(j) - 'a' .charCodeAt(0)].push(s.charCodeAt(j) - 'a' .charCodeAt(0));
In[s.charCodeAt(j) - 'a' .charCodeAt(0)]++;
prev = s;
continue ;
}
if (prev.length > s.length) {
document.write( "Impossible" );
return ;
}
prev = s;
}
let stk = [];
for (let i = 0; i < MAX_CHAR; ++i)
if (In[i] == 0)
stk.push(i);
let out = [];
let vis = new Array(26).fill( false );
while (stk.length > 0) {
let x = stk.pop();
vis[x] = true ;
out.push(String.fromCharCode(x + 'a' .charCodeAt(0)));
for (let i = 0; i < adj[x].length; ++i) {
if (vis[adj[x][i]])
continue ;
In[adj[x][i]]--;
if (In[adj[x][i]] == 0)
stk.push(adj[x][i]);
}
}
for (let i = 0; i < MAX_CHAR; ++i)
if (!vis[i]) {
document.write( "Impossible" );
return ;
}
for (let i = 0; i < out.length; ++i)
document.write(out[i]);
}
let v = [ "efgh" , "abcd" ];
findOrder(v);
</script>
|
Output
zyxwvutsrqponmlkjihgfeadcb
The complexity of this approach is O(N*|S|) + O(V+E), where |V|=26 (number of nodes is the same as number of alphabets) and |E|<N (since at most 1 edge is created for each word as input). Hence overall complexity is O(N*|S|+N). |S| represents the length of each word.
Auxiliary Space: O(MAX_CHAR)
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!
Last Updated :
22 Feb, 2023
Like Article
Save Article