Open In App

Lexicographically smallest and largest string possible via Transitive mapping

Last Updated : 27 Jan, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

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>


Output

aruaaaaa truttttt

Time Complexity: O(M + N*26), where M and N are lengths of string str1 and str3.
Auxiliary Space: O(26)



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads