Open In App

Lexicographically minimum String possible

Last Updated : 11 Oct, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given three strings, S1, S2, and S3. The characters at the same index in S1 and S2 are considered equivalent and follow the transitive property, the task is to find and print the lexicographically smallest string that you can obtain from S3 by changing its characters to some other equivalent character obtained from S1 and S2. In other words, you need to replace the characters in S3 with their equivalent characters from S1 and S2 while maintaining the lexicographic order.

Examples:

Input: S1 = “abc” , S2 = “xyz” , S3 =” xazy”
Output: aacb
Explanation: ‘x’ replaced by ‘a’, ‘y’ is replaced by ‘b’ and ‘z’ is replaced by ‘c’

Input: S1 = “abc” , S2 = “xcd” , S3 =” xdc”
Output: abb
Explanation: {a, x} are equivalent, and {b, c, d} are equivalent, so x is replaced with a, d is replaced with b, and c is replaced with b.

Naïve approach: We can solve this problem using the below idea:

  • Create a graph where s1[i] is connected with s2[i].
  • then traverse string s3 from left to right and do the following.
    • Call DFS for the s3[i] node and calculate the minimum character we can reach from node s3[i].
    • assign this minimum character to s3[i].
  • return string s3.

Time Complexity: O(N2)
Auxiliary Space: O ( 1 )

Efficient Approach: We can solve this problem optimally using the below idea:

Idea is to use the DSU {Disjoint Set Union}. We can connect the two characters which are mapped with each other and at the end we traverse the s3 string and assign every s3[i] to the parent of s3[i].

Follow the steps to solve the problem:

  • Make a node for every character.
  • Traverse in the string s1 and do Union of s1[i] with s2[i].
  • When all Union operation is being done.
  • Traverse in the s3 string and for every character of s3[i], assign it to its parent.
  • Return the s3 string.

Below is the C++ implementation of the above idea :

C++




// C++ code for the above approach:
 
#include <bits/stdc++.h>
using namespace std;
 
// Parent array
int parent[1000];
 
// Size array
int size[1000];
void make(int n)
{
    parent[n] = n;
    size[n] = 1;
}
 
// Find function
int find(int n)
{
    if (n == parent[n])
        return n;
    return parent[n] = find(parent[n]);
}
 
// Union function
void Union(int a, int b)
{
    a = find(a);
    b = find(b);
 
    // Union of two components which
    // are not connected
    if (a != b) {
 
        // If a is greater than b so we swap
        // them to make a always smaller and
        // we have made a as parent of
        // that component
        if (a > b)
            swap(a, b);
        parent[b] = a;
        size[a] += size[b];
    }
}
 
string solve(string s1, string s2, string s3)
{
 
    // Creating nodes for every characters
    for (char ch = 'a'; ch <= 'z'; ch++)
        make(ch);
 
    // Doing union of s1[i] and s2[i]
    for (int i = 0; i < s1.length(); i++) {
        Union(s1[i], s2[i]);
    }
 
    // Finding and assigning the smallest
    // value to s3[i]
    for (int i = 0; i < s3.length(); i++) {
        s3[i] = find(s3[i]);
    }
 
    // Return the s3 string
    return s3;
}
 
// Driver Code
int main()
{
    string s1, s2, s3;
    s1 = "abc";
    s2 = "xcd";
    s3 = "xdc";
 
    // Function call
    cout << solve(s1, s2, s3);
    return 0;
}


Java




import java.io.*;
import java.util.HashMap;
import java.util.Map;
 
public class GFG {
 
    private Map<Character, Character> parent;
    private Map<Character, Integer> size;
 
    public GFG() {
        parent = new HashMap<>();
        size = new HashMap<>();
    }
 
    private void make(Character n) {
        parent.put(n, n);
        size.put(n, 1);
    }
 
    private Character find(Character n) {
        if (n.equals(parent.get(n)))
            return n;
        return parent.put(n, find(parent.get(n)));
    }
 
    private void Union(Character a, Character b) {
        a = find(a);
        b = find(b);
 
        if (!a.equals(b)) {
            if (a > b) {
                Character temp = a;
                a = b;
                b = temp;
            }
            parent.put(b, a);
            size.put(a, size.get(a) + size.get(b));
        }
    }
 
    private String solve(String s1, String s2, String s3) {
        for (char ch = 'a'; ch <= 'z'; ch++) {
            make(ch);
        }
 
        for (int i = 0; i < s1.length(); i++) {
            Union(s1.charAt(i), s2.charAt(i));
        }
 
        StringBuilder result = new StringBuilder();
        for (int i = 0; i < s3.length(); i++) {
            result.append(find(s3.charAt(i)));
        }
 
        return result.toString();
    }
 
    public static void main(String[] args) {
        GFG dsu = new GFG();
 
        String s1 = "abc";
        String s2 = "xcd";
        String s3 = "xdc";
 
        // Function call
        System.out.println(dsu.solve(s1, s2, s3));
    }
}


Python3




# Python code for the above approach:
 
# Parent dictionary
parent = {}
 
# Size dictionary
size = {}
 
def make(n):
    parent[n] = n
    size[n] = 1
 
# Find function
def find(n):
    if n == parent[n]:
        return n
    parent[n] = find(parent[n])
    return parent[n]
 
# Union function
def Union(a, b):
    a = find(a)
    b = find(b)
 
    # Union of two components which
    # are not connected
    if a != b:
 
        # If a is greater than b so we swap
        # them to make a always smaller and
        # we have made a as parent of
        # that component
        if a > b:
            a, b = b, a
        parent[b] = a
        size[a] += size[b]
 
def solve(s1, s2, s3):
 
    # Creating nodes for every characters
    for ch in range(ord('a'), ord('z')+1):
        make(chr(ch))
 
    # Doing union of s1[i] and s2[i]
    for i in range(len(s1)):
        Union(s1[i], s2[i])
 
    # Finding and assigning the smallest
    # value to s3[i]
    new_s3 = ""
    for i in range(len(s3)):
        new_s3 += find(s3[i])
 
    # Return the modified s3 string
    return new_s3
 
# Driver Code
if __name__ == "__main__":
    s1 = "abc"
    s2 = "xcd"
    s3 = "xdc"
 
    # Function call
    print(solve(s1, s2, s3))
# This code is contributed by Sakshi


C#




// C# code for the above approach:
 
using System;
 
class UnionFind
{
    private int[] parent;
    private int[] size;
 
    public UnionFind(int n)
    {
        // Initialize parent and size arrays
        parent = new int[n];
        size = new int[n];
        for (int i = 0; i < n; i++)
        {
            // Initially, each element is its own parent
            parent[i] = i;
            // Size of each component is 1 at the beginning
            size[i] = 1;
        }
    }
 
    public int Find(int n)
    {
        // Find the root of the component containing 'n'
        if (n == parent[n])
            return n;
        // Path compression: Update the parent to the root
        return parent[n] = Find(parent[n]);
    }
 
    public void Union(int a, int b)
    {
        a = Find(a);
        b = Find(b);
 
        if (a != b)
        {
            if (a > b)
                Swap(ref a, ref b);
            // Union of two components by making 'a' the parent
            parent[b] = a;
            // Update the size of the component 'a'
            size[a] += size[b];
        }
    }
 
    private static void Swap(ref int a, ref int b)
    {
        // Helper function to swap two integers
        int temp = a;
        a = b;
        b = temp;
    }
}
 
class Program
{
    static string Solve(string s1, string s2, string s3)
    {
        int n = 26; // Number of characters (a to z)
        UnionFind uf = new UnionFind(n);
 
        // Union operation for corresponding characters in s1 and s2
        for (int i = 0; i < s1.Length; i++)
        {
            uf.Union(s1[i] - 'a', s2[i] - 'a');
        }
 
        char[] result = new char[s3.Length];
        for (int i = 0; i < s3.Length; i++)
        {
            // Find the representative character for each character in s3
            result[i] = (char)('a' + uf.Find(s3[i] - 'a'));
        }
 
        // Return the resulting string
        return new string(result);
    }
 
    static void Main()
    {
        string s1 = "abc";
        string s2 = "xcd";
        string s3 = "xdc";
 
        // Call the Solve function and print the result
        string result = Solve(s1, s2, s3);
        Console.WriteLine(result);
    }
}
 
// this code is contributed by uttamdp_10


Javascript




// Javascript code for the above approach:
 
// Parent dictionary (using JavaScript objects)
const parent = {};
 
// Size dictionary (using JavaScript objects)
const size = {};
 
function make(n) {
  parent[n] = n;
  size[n] = 1;
}
 
function find(n) {
  if (n === parent[n]) {
    return n;
  }
  parent[n] = find(parent[n]);
  return parent[n];
}
 
function Union(a, b) {
  a = find(a);
  b = find(b);
 
  if (a !== b) {
    if (a > b) {
      [a, b] = [b, a]; // Swap a and b
    }
    parent[b] = a;
    size[a] += size[b];
  }
}
 
function solve(s1, s2, s3) {
  // Creating nodes for every characters
  for (let ch = 'a'.charCodeAt(0); ch <= 'z'.charCodeAt(0); ch++) {
    make(String.fromCharCode(ch));
  }
 
  // Doing union of s1[i] and s2[i]
  for (let i = 0; i < s1.length; i++) {
    Union(s1.charAt(i), s2.charAt(i));
  }
 
  // Finding and assigning the smallest
  // value to s3[i]
  let new_s3 = "";
  for (let i = 0; i < s3.length; i++) {
    new_s3 += find(s3.charAt(i));
  }
 
  // Return the modified s3 string
  return new_s3;
}
 
// Driver Code
const s1 = "abc";
const s2 = "xcd";
const s3 = "xdc";
 
// Function call
console.log(solve(s1, s2, s3));


Output

abb






Time Complexity: O(N)
Auxiliary Space: O(1), because the number of nodes can never exceed 26 (number of alphabets).



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads