Lexicographically smallest string with period K possible by replacing ‘?’s from a given string


A string is a period of K if and only if it repeats itself every K characters. For example, the string "abcabcabc" is a period of 3, because it repeats itself every 3 characters. The string "abcabc?abc" is not a period of 3, because the character '?' does not repeat itself every 3 characters.

Problem Statement

Given a string "str" containing N lowercase characters and a positive integer K, the objective is to replace every occurrence of the character '?' within the string "str" with a lowercase alphabet such that the resulting string forms a period of length K. If it is not feasible to find a string that meets the given conditions, the program should output "-1".

The string str can contain any number of lowercase characters, including ‘a’, ‘b’, ‘c’, …, ‘z’.

The string str can also contain the character ‘?’.

The positive integer K must be greater than or equal to 1.

The program should print “-1” if it is not possible to find a string that satisfies the given conditions.

Example

Input

“aabb????”, K = 4

Output

aabbaabb

Input

“xxyy????”, K = 2

Output

-1

Solution Approach

An intuitive approach to find the modified string can be achieved by following the steps listed below.

Generate all possible combinations of replacements for the '?' characters in the given string.

  • For each combination, replace the '?' characters accordingly.

  • Check if the resulting string has a period of K. If yes, store it as a candidate solution.

  • After checking all combinations, compare the candidate solutions and select the lexicographically smallest one.

  • Return the lexicographically smallest string with a period of K, or "-1" if no valid solution is found.

The naive approach involves generating all possible combinations, which can be computationally expensive. As the length of the string and the count of '?' characters increase, the count of combinations grows exponentially. Therefore, this approach is not efficient for large input strings.

A more optimized approach is to use an efficient algorithm which avoids the exhaustive generation of combinations and directly modifies the string based on certain conditions to obtain the lexicographically smallest string with a period of K.

Algorithm

  • Accept a string str and an integer K as parameters.

  • Verify if the length of the string "str" is a multiple of K. If it is not, return "-1" as it is not possible to form a period of length K.

  • Iterate over the range from 0 to K using the variable "i".

  • Create an empty map called "char_freq" to store the frequency count of characters.

  • Traverse through the string "str" starting from index "i" with an increment of K in each iteration.

  • Update the frequency count of each character encountered in the "char_freq" map.

  • If the size of char_freq is greater than 2, return "-1".

  • If the size of char_freq is 1, check if the frequency of '?' is not zero. If so, replace all '?' characters in str at positions i, i+K, i+2K, and so on, with 'a'.

  • Otherwise, if the size of char_freq is 2, find the character other than '?' and store it in ch.

  • Replace all '?' characters in str at positions i, i+K, i+2K, and so on, with ch.

  • Return the modified string str.

Example: C++ Program

The code snippet "stringNew()" is designed to take a string "str" and an integer "K" as inputs. Initially, the function verifies whether the length of "str" is divisible by "K". In case it is not, the function returns -1. However, if the length condition is met, the function proceeds by iterating over the range [0, K]. For each index "i" within this range, the function creates a map called "char_freq" to track the frequency of each character found in the substring "str[i: i + K]". The function then examines whether the size of "char_freq" exceeds 2. If this condition is true, the function returns -1. On the other hand, if the condition is not met, the function replaces all occurrences of '?' within the substring by utilizing the most frequent character stored in "char_freq". Finally, the modified "str" is returned by the function.

Example

#include <iostream>
#include <string>
#include <map>
using namespace std;

string stringNew(string &str, int K){
   // Verify whether the length of the string "str" is divisible by K.
   if (str.length() % K != 0){
      return "-1";
   }
   // Perform an iteration over the interval [0, K].
   for (int i = 0; i < K; i++){
      // Create a map to hold the frequency of characters in the substring str[i: i + K].
      map<char, int> char_freq;
      // Iterate over the string with increment of K in every iteration.
      for (int j = i; j < str.length(); j += K){
         char_freq[str[j]]++;
      }
      // If there are more than two different characters in the substring.
      if (char_freq.size() > 2){
         return "-1";
      }
      // If there is only one character in the substring.
      else if (char_freq.size() == 1){
         // If the character is '?', replace all occurrences of '?' in the substring with 'a'.
         if (char_freq['?'] != 0){
            for (int j = i; j < str.length(); j += K){
               str[j] = 'a';
            }
         }
      }
      // If there are two different characters in the substring.
      else{
         // Find a character other than '?'.
         char ch;
         for (auto &x : char_freq){
            if (x.first != '?'){
               ch = x.first;
            }
         }
         // Exchange all occurrences of '?' in the substring with ch.
         for (int j = i; j < str.length(); j += K){
            str[j] = ch;
         }
      }
   }
   // Return the modified string.
   return str;
}
int main(){
   string str = "aabb????";
   int K = 4;
   cout << "original string: "<< str << " and "<< "K = 4" <<endl;
   cout <<"new string: "<< stringNew(str, K) << endl;
   return 0;
}

Output

original string: aabb???? and K = 4
new string: aabbaabb

Time and Space Complexity Analysis

Time Complexity: O(N)

  • The code consists of nested loops. The outer loop iterates over the range [0, K], and the inner loop iterates over the string with an increment of K.

  • The complexity of the outer loop is O(K) since it iterates K times.

  • The inner loop iterates over a fraction of the string, specifically the characters at positions i, i+K, i+2K, ..., up to the end of the string. The inner loop iterates a number of times determined by the length of the string, N, and the value of K.

  • Overall, the time complexity of the code is O(K * N/K) = O(N).

  • The code allocates additional space to store the frequency of characters in the substring at each position "i". This storage is accomplished using a map named "char_freq".

  • The map "char_freq" is utilized to record the frequencies of characters encountered within the substring. Since the substring can consist of a maximum of two characters (including '?' and another character), the map will only store frequencies for these distinct characters.

  • The space required by the map "char_freq" is directly proportional to the number of distinct characters present in the substring, which in this case is a maximum of 2.

  • As a result, the space complexity of the code can be regarded as O(1) because the space usage remains constant and is not influenced by the size of the input.

Conclusion

The article offers a naive as well as an efficient approach to the problem. The article provides the solution approach, the algorithm used and the C++ program solution as well, along with an in depth analysis of its time complexity and space complexity.

Updated on: 27-Aug-2023

166 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements