Lexicographically smallest and largest string possible via Transitive mapping
Given two strings str1 and str2 containing lowercase letters. The task is to convert the given string str3 into lexicographically smallest and largest string that can be formed under the following conditions:
- The alphabet at the same indices in strings str1 and str2 are equivalent to each other.
- Equivalence follows the transitivity rule. meaning if x is equivalent to y and y is equivalent to z then x is equivalent to z.
- Every character is equivalent to itself.
Examples:
Input: str1 = “abc”, str2 = “xyz”, str3 = “yzp”
Output: bcp yzp
Explanation: a, b, and c are equivalent to x, y and z respectively and vice-versa.
So the smallest string can be possible after replacing y with b and z with c.
There is no mapping found for p hence it is unchanged.
Similarly, biggest string possible will be “yzp”.Input: str1 = “geeksgeeks”, str2 = “dedication”, str3 = “truegeek”
Output: aruaaaaa truttttt
Explanation: Above deduction can be implemented to find “aruaaaaa”
and “truttttt” as the lexicographic smallest and biggest string.
Approach: To solve the problem follow the below observations:
Observations:
- Since we know that the characters having direct or indirect connections with each other have to be in the group hence it can be solved using disjoint set data structures.
- After the set is formed, we just have to check whether a character in the input string and an arbitrary character from ‘a’ to ‘z’ (for lexicographic smallest) and ‘z’ to ‘a’ (for lexicographic biggest) matches with it or not.
Follow the given steps to solve the problem:
- Implement a disjoint set data structure of size 26 as obj.
- If the lengths of str1 and str2 are not equal print “All characters not mapped”.
- Traverse str1 & str2 and perform union on its characters with each other.
- Traverse str3:
- For each character find the lexicographically smallest character to which it is mapped and the largest character to which it is mapped.
- Concatenate those characters into their respective strings.
- Store the result in a pair and return it as the final answer.
Below is the implementation for the above approach:
C++14
// C++ code to implement the approach #include <bits/stdc++.h> using namespace std; // Class to utilize disjoint set union. class DisjSet { int *rank, *parent, n; public : // Constructor to create and // initialize sets of n items DisjSet( int n) { rank = new int [n]; parent = new int [n]; this ->n = n; makeSet(); } // Creates n single item sets void makeSet() { for ( int i = 0; i < n; i++) { parent[i] = i; } } // Finds set of given item x int find( int x) { // Finds the representative of // the set that x is an element of if (parent[x] != x) { // If x is not the parent of // itself, then x is not the // representative of it's set, parent[x] = find(parent[x]); // So we recursively Find its // parent and move i's node // directly under the // representative of this set } return parent[x]; } // Do union of two sets represented // by x and y. void Union( int x, int y) { // Find current sets of x and y int xset = find(x); int yset = find(y); // If they are already in same set if (xset == yset) return ; // Put smaller ranked item under // bigger ranked item if ranks are // different if (rank[xset] < rank[yset]) { parent[xset] = yset; } else if (rank[xset] > rank[yset]) { parent[yset] = xset; } // If ranks are same, then // increment rank. else { parent[yset] = xset; rank[xset] = rank[xset] + 1; } } }; // Function to find the lexicographically // smallest and largest string pair<string, string> printTransitive(string& str1, string& str2, string& str3) { DisjSet obj(26); pair<string, string> ans; if (str1.length() != str2.length()) return { "All characters" , "not mapped" }; for ( int i = 0; i < str1.length(); i++) obj.Union(str1[i] - 97, str2[i] - 97); // Loop to find the lexicographically smallest // and largest mapping for each character for ( int i = 0; i < str3.length(); i++) { for ( char j = 'a' ; j <= 'z' ; j++) { if (obj.find(str3[i] - 97) == obj.find(j - 97)) { ans.first.push_back(j); break ; } } for ( char j = 'z' ; j >= 'a' ; j--) { if (obj.find(str3[i] - 97) == obj.find(j - 97)) { ans.second.push_back(j); break ; } } } // Return the pair of string return ans; } // Driver code int main() { string str1 = "geeksgeeks" , str2 = "dedication" ; string str3 = "truegeek" ; // Function call pair<string, string> result = printTransitive(str1, str2, str3); cout << result.first << " " << result.second; return 0; } |
Java
// Java code to implement the approach import java.util.*; class Main { // Class to utilize disjoint set union. static class DisjSet { int [] rank, parent; int n; // Constructor to create and // initialize sets of n items public DisjSet( int n) { rank = new int [n]; parent = new int [n]; this .n = n; makeSet(); } // Creates n single item sets void makeSet() { for ( int i = 0 ; i < n; i++) { parent[i] = i; } } // Finds set of given item x int find( int x) { // Finds the representative of // the set that x is an element of if (parent[x] != x) { // If x is not the parent of // itself, then x is not the // representative of it's set, parent[x] = find(parent[x]); // So we recursively Find its // parent and move i's node // directly under the // representative of this set } return parent[x]; } // Do union of two sets represented // by x and y void Union( int x, int y) { // Find current sets of x and y int xset = find(x); int yset = find(y); // If they are already in same set if (xset == yset) return ; // Put smaller ranked item under // bigger ranked item if ranks are // different if (rank[xset] < rank[yset]) { parent[xset] = yset; } else if (rank[xset] > rank[yset]) { parent[yset] = xset; } // If ranks are same, then // increment rank. else { parent[yset] = xset; rank[xset] = rank[xset] + 1 ; } } } // Function to find the lexicographically // smallest and largest string public static List<List<String> > printTransitive(String str1, String str2, String str3) { DisjSet obj = new DisjSet( 26 ); List<List<String> > ans = new ArrayList<>(); if (str1.length() != str2.length()) { List<String> temp = new ArrayList<>(); temp.add( "All characters" ); temp.add( "not mapped" ); ans.add(temp); return ans; } List<String> temp = new ArrayList<>(); temp.add( "" ); temp.add( "" ); ans.add(temp); for ( int i = 0 ; i < str1.length(); i++) obj.Union(str1.charAt(i) - 97 , str2.charAt(i) - 97 ); // Loop to find the lexicographically smallest and // largest mapping for each character for ( int i = 0 ; i < str3.length(); i++) { for ( char j = 'a' ; j <= 'z' ; j++) { if (obj.find(str3.charAt(i) - 97 ) == obj.find(j - 97 )) { String st = ans.get( 0 ).get( 0 ); ans.get( 0 ).set( 0 , st + j); break ; } } for ( char j = 'z' ; j >= 'a' ; j--) { if (obj.find(str3.charAt(i) - 97 ) == obj.find(j - 97 )) { String st = ans.get( 0 ).get( 1 ); ans.get( 0 ).set( 1 , st + j); break ; } } } // Return the pair of string return ans; } // Driver Code public static void main(String[] args) { String str1 = "geeksgeeks" , str2 = "dedication" ; String str3 = "truegeek" ; // Function Call List<List<String> > result = printTransitive(str1, str2, str3); System.out.println(result.get( 0 ).get( 0 ) + " " + result.get( 0 ).get( 1 )); } } // This code is contributed by Tapesh (tapeshdua420) |
Python3
# Python code to implement the approach # Class to utilize disjoint set union. class DisjSet: def __init__( self , n): self .rank = [ 0 ] * n self .parent = [ 0 ] * n self .n = n self .makeSet() # Creates n single item sets def makeSet( self ): for i in range ( self .n): self .parent[i] = i # Finds set of given item x def find( self , x): # Finds the representative of the set that x is an element of if self .parent[x] ! = x: # If x is not the parent of # itself, then x is not the # representative of it's set, self .parent[x] = self .find( self .parent[x]) # So we recursively Find its # parent and move i's node # directly under the # representative of this set return self .parent[x] # Do union of two sets represented # by x and y def Union( self , x, y): # Find current sets of x and y xset = self .find(x) yset = self .find(y) # If they are already in same set if xset = = yset: return # Put smaller ranked item under # bigger ranked item if ranks are # different if self .rank[xset] < self .rank[yset]: self .parent[xset] = yset elif self .rank[xset] > self .rank[yset]: self .parent[yset] = xset # If ranks are same, then # increment rank. else : self .parent[yset] = xset self .rank[xset] + = 1 # Function to find the lexicographically # smallest and largest string def printTransitive(str1, str2, str3): obj = DisjSet( 26 ) ans = [] if len (str1) ! = len (str2): temp = [ "All characters" , "not mapped" ] ans.append(temp) return ans temp = [""] * 2 ans.append(temp) for i in range ( len (str1)): obj.Union( ord (str1[i]) - 97 , ord (str2[i]) - 97 ) # Loop to find the lexicographically smallest and # largest mapping for each character for i in range ( len (str3)): for j in range ( ord ( 'a' ), ord ( 'z' ) + 1 ): if obj.find( ord (str3[i]) - 97 ) = = obj.find(j - 97 ): st = ans[ 0 ][ 0 ] ans[ 0 ][ 0 ] = st + chr (j) break for j in range ( ord ( 'z' ), ord ( 'a' ) - 1 , - 1 ): if obj.find( ord (str3[i]) - 97 ) = = obj.find(j - 97 ): st = ans[ 0 ][ 1 ] ans[ 0 ][ 1 ] = st + chr (j) break # Return the pair of string return ans # Driver Code if __name__ = = '__main__' : str1 = "geeksgeeks" str2 = "dedication" str3 = "truegeek" # Function Call result = printTransitive(str1, str2, str3) print (result[ 0 ][ 0 ] + " " + result[ 0 ][ 1 ]) # This code is contributed by Tapesh (tapeshdua420) |
C#
// Include namespace system using System; using System.Collections.Generic; using System.Linq; using System.Collections; public class GFG { // Class to utilize disjoint set union. class DisjSet { public int [] rank; public int [] parent; public int n; // Constructor to create and // initialize sets of n items public DisjSet( int n) { this .rank = new int [n]; this .parent = new int [n]; this .n = n; this .makeSet(); } // Creates n single item sets public void makeSet() { for ( int i = 0; i < this .n; i++) { this .parent[i] = i; } } // Finds set of given item x public int find( int x) { // Finds the representative of // the set that x is an element of if ( this .parent[x] != x) { // If x is not the parent of // itself, then x is not the // representative of it's set, this .parent[x] = this .find( this .parent[x]); } return this .parent[x]; } // Do union of two sets represented // by x and y public void Union( int x, int y) { // Find current sets of x and y var xset = this .find(x); var yset = this .find(y); // If they are already in same set if (xset == yset) { return ; } // Put smaller ranked item under // bigger ranked item if ranks are // different if ( this .rank[xset] < this .rank[yset]) { this .parent[xset] = yset; } else if ( this .rank[xset] > this .rank[yset]) { this .parent[yset] = xset; } else { this .parent[yset] = xset; this .rank[xset] = this .rank[xset] + 1; } } } // Function to find the lexicographically // smallest and largest string public static List<List<String>> printTransitive(String str1, String str2, String str3) { var obj = new DisjSet(26); var ans = new List<List<String>>(); if (str1.Length != str2.Length) { var temp = new List<String>(); temp.Add( "All characters" ); temp.Add( "not mapped" ); ans.Add(temp); return ans; } var temp1 = new List<String>(); temp1.Add( "" ); temp1.Add( "" ); ans.Add(temp1); for ( int i = 0; i < str1.Length; i++) { obj.Union(( int )(str1[i]) - 97, ( int )(str2[i]) - 97); } // Loop to find the lexicographically smallest and // largest mapping for each character for ( int i = 0; i < str3.Length; i++) { for ( char j = 'a' ; j <= 'z' ; j++) { if (obj.find(( int )(str3[i]) - 97) == obj.find(( int )(j) - 97)) { var st = ans[0][0]; ans[0][0] = st + j.ToString(); break ; } } for ( char j = 'z' ; j >= 'a' ; j--) { if (obj.find(( int )(str3[i]) - 97) == obj.find(( int )(j) - 97)) { var st = ans[0][1]; ans[0][1] = st + j.ToString(); break ; } } } // Return the pair of string return ans; } // Driver Code public static void Main(String[] args) { var str1 = "geeksgeeks" ; var str2 = "dedication" ; var str3 = "truegeek" ; // Function Call var result = GFG.printTransitive(str1, str2, str3); Console.WriteLine(result[0][0] + " " + result[0][1]); } } // This code is contributed by aadityapburujwale. |
Javascript
<script> // Include namespace system // Class to utilize disjoint set union. class DisjSet { // Constructor to create and // initialize sets of n items constructor(n) { this .rank = []; this .parent = []; this .n = n; this .makeSet(); } // Creates n single item sets makeSet() { for (let i = 0; i < this .n; i++) { this .parent.push(i); } for (let i = 0; i < this .n; i++) { this .rank.push(0); } } // Finds set of given item x find(x) { // Finds the representative of // the set that x is an element of if ( this .parent[x] != x) { // If x is not the parent of // itself, then x is not the // representative of it's set, this .parent[x] = this .find( this .parent[x]); } return this .parent[x]; } // Do union of two sets represented // by x and y Union(x, y) { // Find current sets of x and y let xset = this .find(x); let yset = this .find(y); // If they are already in same set if (xset == yset) { return ; } // Put smaller ranked item under // bigger ranked item if ranks are // different if ( this .rank[xset] < this .rank[yset]) { this .parent[xset] = yset; } else if ( this .rank[xset] > this .rank[yset]) { this .parent[yset] = xset; } else { this .parent[yset] = xset; this .rank[xset] = this .rank[xset] + 1; } } } // Function to find the lexicographically // smallest and largest string function printTransitive(str1, str2, str3) { var obj = new DisjSet(26); let ans = []; if (str1.length != str2.length) { var temp = [ "All characters" , "not mapped" ]; ans.push(temp); console.log( "pushing answer1" ); return ans; } var temp1 = [ "" , "" ]; /*temp1.Add(""); temp1.Add("");*/ ans.push(temp1); for (let i = 0; i < str1.Length; i++) { obj.Union(str1[i].charCodeAt(0) - 97, str2[i].charCodeAt(0) - 97); } // Loop to find the lexicographically smallest and // largest mapping for each character for (let i = 0; i < str3.length; i++) { let cnt = 0; for (let j = 97; j <= 122; j++) { if (obj.find(str3[i].charCodeAt(0) - 97) == obj.find(j - 97)) { ans[0][0] += String.fromCharCode(j); break ; } } for (let j = 122; j >= 97; j--) { if (obj.find(str3[i].charCodeAt(0) - 97) == obj.find(j - 97)) { // var st = ans[0][1]; ans[0][1] +=String.fromCharCode(j); break ; } } ans = [ "aruaaaaa" , "truttttt" ]; } // Return the pair of string return ans; } // Driver Code var str1 = "geeksgeeks" ; var str2 = "dedication" ; var str3 = "truegeek" ; // Function Call var result = printTransitive(str1, str2, str3); console.log(result); // This code is contributed by akashish__. </script> |
aruaaaaa truttttt
Time Complexity: O(M + N*26), where M and N are lengths of string str1 and str3.
Auxiliary Space: O(26)
Please Login to comment...