Lexicographically largest possible by merging two strings by adding one character at a time


Lexicographic means the algorithm by using which we can arrange given words in alphabetical order, the same concept which is used in dictionaries. The largest possible string that we would get by merging two strings taking one-character element at a time so that the order is lexicographic can be obtained by arranging alphabets in decreasing order or descending order keeping the sequence of elements in mind.

Problem Statement

Now, in this problem, we need to find lexicographically the largest possible string we get by merging two given strings. To understand this problem, we should know the basic concept we use for arranging strings in lexicographic order.

Let’s try to understand this problem with the help of some examples.

Input

string1 = "cabaa", string2 = "bcaaa"

Output

"cbcabaaaaa"

Explanation

One way to get the lexicographically largest merged string is −

  • Take from string1 “c” and append this in an initial empty string, this leaves us with string1 “abaa” and string2 “bcaaa”

  • Now, take from string2 “b” making the merged string “cb” and leaving string1 as “abaa” and string2 as “caaa”

  • Again take from string2 “c” making the merged string “cbc” and leaving string1 as “abaa” and string2 as “aaa”

  • Take from string1 “a” making the merged string “cbca” and leaving string1 as “baa” and string2 as “aaa”

  • Again take from string1 “b” making the merged string “cbcab” and leaving string1 as “aa” and string2 as “aaa”

  • Now, append all remaining a’s from string1 and string2 to the merged string to get the end result.

Input

string1 = "baa", string2 = "bcaac"

Output

"bcbaacaa"

Explanation

Here, to get the lexicographically largest merged string we will take an element from string2 ”b” and then again from string2 making it “bc”. Now, we will take “b” from string1 making the merged string “bcb” rest we will pick “aac” from string2 and “aa” from string1 making the merged string “bcbaacaa” as the expected output.

Problem Explanation

Let’s try to understand the problem and find its solution. We can solve this problem by two approaches: one by using recursion and the other by using iteration in which we would use the concept of greedy pointers. Greedy pointers are the use of pointers when we would make an optimal choice at a small step to get an overall optimal solution as a whole.

Approach 1 - Brute force recursive solution

Here, we will use the concept of the recursive function where the base condition is defined when the size of either of the two strings becomes zero. Then we will compare the first character of the remaining strings whichever is greater will be returned in combination with a call to the function where its substring is called.

Example

Now, let us implement the above approach in different programming languages: C, C++, Java, and Python −

#include<bits/stdc++.h>
using namespace std;
// Make a function to get the Lexicographically largest possible string
string helper(string word1, string word2) {
   // base condition for recursion
   if (word1.empty() || word2.empty()){
      return word1 + word2;
   }
   // Check the character from which string would be chosen first among both strings
   if (word1 > word2) {
      return word1[0] + helper(word1.substr(1), word2);
   }
   // return the final answer which would provide optimal result
   return word2[0] + helper(word1, word2.substr(1));
}
int main() {
   // Give two strings by the user
   string string1 = "cabaa";
   string string2 = "bcaaa";
   // Call the helper function 
   cout << "The lexicographically largest possible string is: " << helper(string1, string2);
   return 0;
}	  

Output

The lexicographically largest possible string is: cbcabaaaaa
public class Main {
   // Function to get the lexicographically largest possible string
   public static String helper(String word1, String word2) {
      // Base condition for recursion
      if (word1.isEmpty() || word2.isEmpty()) {
         return word1 + word2;
      }

      // Check the character from which string would be chosen first among both strings
      if (word1.compareTo(word2) > 0) {
         return word1.charAt(0) + helper(word1.substring(1), word2);
      }

      // Return the final answer which would provide the optimal result
      return word2.charAt(0) + helper(word1, word2.substring(1));
   }
   public static void main(String[] args) {
      // Provide two strings
      String string1 = "cabaa";
      String string2 = "bcaaa";

      // Call the helper function
      String result = helper(string1, string2);

      // Print the lexicographically largest possible string
      System.out.println("The lexicographically largest possible string is: " + result);
   }
}

Output

The lexicographically largest possible string is: cbcabaaaaa
# Function to get the lexicographically largest possible string
def helper(word1, word2):
   # Base condition for recursion
   if not word1 or not word2:
      return word1 + word2
    
   # Check the character from which string would be chosen first among both strings
   if word1 > word2:
      return word1[0] + helper(word1[1:], word2)
    
   # Return the final answer which would provide the optimal result
   return word2[0] + helper(word1, word2[1:])

# Main function
def main():
   # Provide two strings
   string1 = "cabaa"
   string2 = "bcaaa"

   # Call the helper function
   result = helper(string1, string2)

   # Print the lexicographically largest possible string
   print("The lexicographically largest possible string is:", result)

if __name__ == "__main__":
   main()

Output

The lexicographically largest possible string is: cbcabaaaaa

Complexities for the Above Code

  • Time complexity − O(m*n); where ‘m’ and ‘n’ are the size of given two strings as the initial input provided by the user. Here is an inbuilt recursion stack that would be used to run through all the given elements present in both strings.

  • Space complexity − O(1); though an inbuilt recursion stack would be used here but still it would not take up space as it is used as a runtime memory.

Approach 2 - Optimal Solution Using Greedy Pointer Technique

Algorithm

  • Run a loop until we reach either the size of the first string(for a variable ‘i’) or else the size of the second string(for a variable ‘j’).

  • Check which character comes later according to ASCII codes and we will append that character to the merged string.

  • After we reach the stopping condition of the loop we will check which among ‘i’ or ‘j’ reached its limit.

  • We will run a separate loop to make the other one reach its stopping point so that we can take the characters of both strings in the merged string.

Example

Now, let us implement the above approach in different programming languages: C, C++, Java, and Python −

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

// Function to get the lexicographically largest possible string
char* helper(const char* word1, const char* word2) {
   int n = strlen(word1);
   int m = strlen(word2);
   char* ans = (char*)malloc(n + m + 1); // Allocate memory for the result string

   int i = 0, j = 0, k = 0;
   
   while (i < n && j < m) {
      // Check which character is maximum
      if (strcmp(&word1[i], &word2[j]) > 0) {
         ans[k++] = word1[i++];
      } else {
         ans[k++] = word2[j++];
      }
   }
   
   // If the condition for 'i' was not satisfied, append the rest of the first string to the final answer
   while (i < n) {
      ans[k++] = word1[i++];
   }
   
   // If the condition for 'j' was not satisfied, append the rest of the second string to the final answer
   while (j < m) {
      ans[k++] = word2[j++];
   }    
   ans[k] = '\0'; // Null-terminate the result string    
   return ans;
}
int main() {
   // Given two strings by the user
   const char* string1 = "cabaa";
   const char* string2 = "bcaaa";
   
   // Call the helper function
   char* result = helper(string1, string2);
   
   // Print the lexicographically largest possible string
   printf("The lexicographically largest possible string is: %s\n", result);
   
   // Free the allocated memory
   free(result);
   
   return 0;
}

Output

The lexicographically largest possible string is: cbcabaaaaa
#include<bits/stdc++.h>
using namespace std;
// Make a function to get the Lexicographically largest possible string
string helper(string word1, string word2) {
   // Define size of string1 and string2
   int i = 0, j = 0, n = word1.size(), m = word2.size();
   string ans;
   // Using the pointer technique
   while(i < n && j < m) {
      // Check which character is maximum
      if(word1.substr(i) > word2.substr(j)){ 
         ans += word1[i];
         i++;
      } else { 
         ans += word2[j];
         j++;
      }
   }
   // If the condition for 'i' was not satisfied append the rest first string to the final answer
   while(i < n){ 
      ans += word1[i];
      i++;
   }
   // If the condition for 'i' was not satisfied append the rest first string to the final answer
   while(j < m){ 
      ans += word2[j];
      j++;
   }
   // return the final answer which would provide the optimal result
   return ans;
}
int main() {
   // Given two strings by the user
   string string1 = "cabaa";
   string string2 = "bcaaa";
   // Call the helper function 
   cout << "The lexicographically largest possible string is: " << helper(string1, string2);
   return 0;
}	  

Output

The lexicographically largest possible string is: cbcabaaaaa
public class Main {
   // Make a function to get the lexicographically largest possible string
   public static String helper(String word1, String word2) {
      int i = 0, j = 0;
      int n = word1.length();
      int m = word2.length();
      StringBuilder ans = new StringBuilder(); // Use StringBuilder to efficiently build the string

      // Using a pointer technique
      while (i < n && j < m) {
         // Check which character is maximum
         if (word1.substring(i).compareTo(word2.substring(j)) > 0) {
            ans.append(word1.charAt(i));
            i++;
         } else {
            ans.append(word2.charAt(j));
            j++;
         }
      }

      // If the condition for 'i' was not satisfied, append the rest of the first string to the final answer
      while (i < n) {
         ans.append(word1.charAt(i));
         i++;
      }

      // If the condition for 'j' was not satisfied, append the rest of the second string to the final answer
      while (j < m) {
         ans.append(word2.charAt(j));
         j++;
      }

      // Return the final answer which provides the optimal result
      return ans.toString();
   }
   public static void main(String[] args) {
      // Given two strings by the user
      String string1 = "cabaa";
      String string2 = "bcaaa";
      // Call the helper function
      System.out.println("The lexicographically largest possible string is: " + helper(string1, string2));
   }
}

Output

The lexicographically largest possible string is: cbcabaaaaa
# Function to get the lexicographically largest possible string
def helper(word1, word2):
   i, j = 0, 0
   n, m = len(word1), len(word2)
   ans = []
   # Using a pointer technique
   while i < n and j < m:
      # Check which character is maximum
      if word1[i:] > word2[j:]:
         ans.append(word1[i])
         i += 1
      else:
         ans.append(word2[j])
         j += 1
   # If the condition for 'i' was not satisfied, append the rest of the first string to the final answer
   while i < n:
      ans.append(word1[i])
      i += 1
   # If the condition for 'j' was not satisfied, append the rest of the second string to the final answer
   while j < m:
      ans.append(word2[j])
      j += 1

   # Join the characters to form the final answer
   return ''.join(ans)

# Main function
def main():
   # Given two strings by the user
   string1 = "cabaa"
   string2 = "bcaaa"
   # Call the helper function
   result = helper(string1, string2)
   print("The lexicographically largest possible string is:", result)

if __name__ == "__main__":
   main()

Output

The lexicographically largest possible string is: cbcabaaaaa

Complexities for the Above Code

  • Time complexity − O(m+n); where ‘m’ and ‘n’ are the size of given two strings as the initial input provided by the user. Here a loop would be used (n + m) times to get the final solution.

  • Space complexity − O(n+m); here a string ‘ans’ is used to store our output which would take up (n+m) size in the memory.

Conclusion

In this article, to find the lexicographically largest possible string by merging two strings, provided to us by the user, by adding one character at a time. Firstly, we will apply the naive approach to get the output with the help of the recursive process. We will ponder upon all the available options of the merged string and recursion would provide us with the most apt output required to satisfy the lexicographic condition keeping the order of two strings in mind. But this approach will take more time to execute the code. So, we will go with another approach, which is iterative, using greedy pointers to enhance time complexity, and through this procedure, we will be able to reach the final output in one iteration go only.

Updated on: 22-Jan-2024

141 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements