Lexicographically smallest String by removing exactly K characters
Given a string S consisting of only lowercase characters, the task is to find the lexicographically smallest string after removing exactly K characters from the string. But you have to modify the value of K, i.e., if the length of the string is a power of 2, reduce K by half, else multiply K by 2. You can remove any K character.
NOTE: If it is not possible to remove K (the value of K after correction) characters or if the resulting string is empty return -1.
Examples:
Input: S = “fooland”, K = 2
Output: “and”
Explanation: As the size of the string = 7, which is not a power of 2, hence K = 4. After removing 4 characters from the given string, the lexicographically smallest string is “and”.Input: S = “code”, K = 4
Output: “cd”
Explanation: As the length of the string = 4, which is 2 to the power 2, hence k = 2. Hence, lexicographically smallest string after removal of 2 characters is “cd”.
Naive Approach: The basic way to solve the problem is as follows:
The idea is to find the smallest (n – K) characters from string using nested loop.
Follow the steps to solve this problem:
- First, correct the value of K by checking the length of the string is in the power of 2 or not.
- To check the length of the string is present in the power of 2 or not we can use the count of BitSet in length.
- If the Count of BitSet is 1 that means string_length has only one bit which means it is in the power of 2.
- If the size of the string is in the power of 2 then divide K by 2 else multiply K by 2.
- Now check if K is greater than or equal to the size of the string then return -1.
- Else, Initialize an array of size string_length with 1 for marking all removed(0) and taken(1) elements.
- Run a loop from 0 to the end of string_length
- Run a nested loop inside the upper loop from the upper loop’s index till index + K and find the smallest character between the range.
- Now run a loop from (smallest character index) – 1 till the upper loop index and marks all index with zero – that means it is removed from the string, here we have to count the number of removed characters as well if it is equal to K then stop.
- Set i = (smallest character index) + 1
- When come out of the loop check count of the removed character is less than K then remove that number of characters from the end of the string and mark that index with zero.
- Now run a loop from 0 to string_length and check if the mark of that index is 1 then add the character[i] into the Ans.
- Return the Ans.
Below is the implementation of the above approach.
C++
// C++ code to implement the approach #include <bits/stdc++.h> using namespace std; // Function to find the setbit count int countSetBits( int n) { int count = 0; while (n) { count += n & 1; n >>= 1; } return count; } // Function to find the lexicographically // smallest possible string string lexicographicallySmallest(string str, int k) { int n = str.size(); // If length is power of 2 // then divide k by 2 if (countSetBits(n) == 1) k /= 2; // Else multiply k with 2 else k *= 2; // If k is greater then size of string // then return -1 if (k >= n) return "-1" ; // a for storing 1 int a[n], i, j; // Mark all position with 1 for (i = 0; i < n; i++) a[i] = 1; // Iterate string for (i = 0; i < n;) { // Starting index int start = i; // Position of start int index = start; // Ending index int end = min(start + k, n - 1); // Initialize min as start char minn = str[start]; // Iterate from start to end for (j = start + 1; j <= end; j++) { // Checking for min and storing // value and index of min if (str[j] < minn) { minn = str[j]; index = j; } } // Mark all max 0 before min for (j = index - 1; j >= start and k != 0; j--) { a[j] = 0; k--; } // Change i to next of last index i = index + 1; } // If k is not zero do the // same as before if (k) { for (i = n - 1; i >= 0 and k != 0; i--) { if (a[i]) { a[i] = 0; k--; } } } // res for storing resulting string string res = "" ; // Storing resulting string for (i = 0; i < n; i++) { if (a[i]) { res += str[i]; } } // Return string return res; } // Driver code int main() { string S = "fooland" ; int K = 2; // Function Call cout << lexicographicallySmallest(S, K) << endl; return 0; } |
Java
// Java implementation import java.io.*; class GFG { // Function to find the setbit count static public int countSetBits( int n) { int count = 0 ; while (n > 0 ) { count += n & 1 ; n >>= 1 ; } return count; } // Function to find the lexicographically // smallest possible string static public String lexicographicallySmallest(String str, int k) { int n = str.length(); // If length is power of 2 // then divide k by 2 if (countSetBits(n) == 1 ) k /= 2 ; // Else multiply k with 2 else k *= 2 ; // If k is greater then size of string // then return -1 if (k >= n) return "-1" ; // a for storing 1 int [] a = new int [n]; int i, j; // Mark all position with 1 for (i = 0 ; i < n; i++) a[i] = 1 ; // Iterate string for (i = 0 ; i < n;) { // Starting index int start = i; // Position of start int index = start; // Ending index int end = Math.min(start + k, n - 1 ); // Initialize min as start char minn = str.charAt(start); // Iterate from start to end for (j = start + 1 ; j <= end; j++) { // Checking for min and storing // value and index of min if (str.charAt(j) < minn) { minn = str.charAt(j); index = j; } } // Mark all max 0 before min for (j = index - 1 ; j >= start && k != 0 ; j--) { a[j] = 0 ; k--; } // Change i to next of last index i = index + 1 ; } // If k is not zero do the // same as before if (k != 0 ) { for (i = n - 1 ; i >= 0 && k != 0 ; i--) { if (a[i] != 0 ) { a[i] = 0 ; k--; } } } // res for storing resulting string String res = "" ; // Storing resulting string for (i = 0 ; i < n; i++) { if (a[i] != 0 ) { res += str.charAt(i); } } // Return string return res; } public static void main(String[] args) { String S = "fooland" ; int K = 2 ; // Function Call System.out.println(lexicographicallySmallest(S, K)); } } // This code is contributed by lokesh. |
Python
# Function to find the setbit count def countSetBits(n): count = 0 while n: count + = n & 1 n >> = 1 return count # Function to find the lexicographically # smallest possible string def lexicographicallySmallest( str , k): n = len ( str ) # If length is power of 2 # then divide k by 2 if countSetBits(n) = = 1 : k / / = 2 # Else multiply k with 2 else : k * = 2 # If k is greater then size of string # then return -1 if k > = n: return "-1" # a for storing 1 a = [ 1 ] * n # Iterate string i = 0 while i < n: # Starting index start = i # Position of start index = start # Ending index end = min (start + k, n - 1 ) # Initialize min as start minn = str [start] # Iterate from start to end for j in range (start + 1 , end + 1 ): # Checking for min and storing # value and index of min if str [j] < minn: minn = str [j] index = j # Mark all max 0 before min for j in range (index - 1 , start - 1 , - 1 ): if k ! = 0 : a[j] = 0 k - = 1 # Change i to next of last index i = index + 1 # If k is not zero do the # same as before if k: for i in range (n - 1 , - 1 , - 1 ): if a[i]: a[i] = 0 k - = 1 # res for storing resulting string res = "" # Storing resulting string for i in range (n): if a[i]: res + = str [i] # Return string return res # Driver code if __name__ = = '__main__' : S = "fooland" K = 2 # Function Call print (lexicographicallySmallest(S, K)) # This code is contributed by aadityamaharshi21. |
C#
// C# implementation using System; public class GFG { // Function to find the setbit count static public int countSetBits( int n) { int count = 0; while (n > 0) { count += n & 1; n >>= 1; } return count; } // Function to find the lexicographically // smallest possible string static public string lexicographicallySmallest( string str, int k) { int n = str.Length; // If length is power of 2 // then divide k by 2 if (countSetBits(n) == 1) k /= 2; // Else multiply k with 2 else k *= 2; // If k is greater then size of string // then return -1 if (k >= n) return "-1" ; // a for storing 1 int [] a = new int [n]; int i, j; // Mark all position with 1 for (i = 0; i < n; i++) a[i] = 1; // Iterate string for (i = 0; i < n;) { // Starting index int start = i; // Position of start int index = start; // Ending index int end = Math.Min(start + k, n - 1); // Initialize min as start char minn = str[start]; // Iterate from start to end for (j = start + 1; j <= end; j++) { // Checking for min and storing // value and index of min if (str[j] < minn) { minn = str[j]; index = j; } } // Mark all max 0 before min for (j = index - 1; j >= start && k != 0; j--) { a[j] = 0; k--; } // Change i to next of last index i = index + 1; } // If k is not zero do the // same as before if (k != 0) { for (i = n - 1; i >= 0 && k != 0; i--) { if (a[i] != 0) { a[i] = 0; k--; } } } // res for storing resulting string string res = "" ; // Storing resulting string for (i = 0; i < n; i++) { if (a[i] != 0) { res += str[i]; } } // Return string return res; } static public void Main() { string S = "fooland" ; int K = 2; // Function Call Console.WriteLine(lexicographicallySmallest(S, K)); } } // This code is contributed by ksam24000 |
Javascript
// JavaScript code to implement the approach // Function to find the setbit count const countSetBits = (n) => { let count = 0; while (n) { count += n & 1; n >>= 1; } return count; } // Function to find the lexicographically // smallest possible string const lexicographicallySmallest = (str, k) => { let n = str.length; // If length is power of 2 // then divide k by 2 if (countSetBits(n) == 1) k = parseInt(k / 2); // Else multiply k with 2 else k *= 2; // If k is greater then size of string // then return -1 if (k >= n) return "-1" ; // a for storing 1 let a = new Array(n).fill(0), i, j; // Mark all position with 1 for (i = 0; i < n; i++) a[i] = 1; // Iterate string for (i = 0; i < n;) { // Starting index let start = i; // Position of start let index = start; // Ending index let end = Math.min(start + k, n - 1); // Initialize min as start let minn = str[start]; // Iterate from start to end for (j = start + 1; j <= end; j++) { // Checking for min and storing // value and index of min if (str[j] < minn) { minn = str[j]; index = j; } } // Mark all max 0 before min for (j = index - 1; j >= start && k != 0; j--) { a[j] = 0; k--; } // Change i to next of last index i = index + 1; } // If k is not zero do the // same as before if (k) { for (i = n - 1; i >= 0 && k != 0; i--) { if (a[i]) { a[i] = 0; k--; } } } // res for storing resulting string let res = "" ; // Storing resulting string for (i = 0; i < n; i++) { if (a[i]) { res += str[i]; } } // Return string return res; } // Driver code let S = "fooland" ; let K = 2; // Function Call console.log(lexicographicallySmallest(S, K)); // This code is contributed by rakeshsahni |
and
Time Complexity: O(N*N), As here we run a nested loop.
Auxiliary Space: O(N), using one array for marking all removed characters.
Optimized Approach: To solve the problem follow the below idea:
The idea is to use stack and maintain at least (n – K) non – decreasing characters starting with the smallest character we found.
Follow the steps to solve this problem:
- First correct the value of K by checking the length of the string is in the power of 2 or not.
- To check the length of the string is present in the power of 2 or not we can use the Bitwise-and operator.
- If Bitwise-and of string_length and (string_length – 1) gives 0 that means string_length has only one bit which means it is in the power of 2.
- If the size of the string is in the power of 2 then divide K by 2 else multiply K by 2.
- Now check if K is greater than or equal to the size of the string then return -1.
- Else, create a stack for storing the characters in non-decreasing order.
- Run a loop and check for every character:
- If the top element of the stack is greater than the char that means we have to consider the string from here because we found here lowest character so we have to remove the char from the stack and decrease K by one till the stack is empty or the stack top element is less than the char and K is greater than zero (because we have to remove only K characters).
- Push the char into the stack
- Check if the number of removed chars is less than K then remove that number of chars from the stack.
- Copy all stack characters into a variable string ans and reverse the ans(because we copied from the stack).
- Return the Ans.
Below is the implementation of the above approach.
C++
// C++ code to implement the approach #include <bits/stdc++.h> using namespace std; // Function to find the lexicographically // smallest string string lexicographicallySmallest(string S, int k) { string ans = "" ; int l = S.length(); if (l & (l - 1)) k += k; else k /= 2; if (k >= l) return "-1" ; stack< char > st; for ( int i = 0; i < l; i++) { while (!st.empty() && k > 0 && st.top() > S[i]) { st.pop(); k--; } st.push(S[i]); } if (k > 0) while (k--) st.pop(); while (!st.empty()) { ans = st.top() + ans; st.pop(); } return ans; } // Driver Code int main() { string S = "fooland" ; int K = 2; // Function Call cout << lexicographicallySmallest(S, K); return 0; } |
Java
// Java code to implement the approach import java.util.*; public class GFG { // Function to find the lexicographically // smallest string public static String lexicographicallySmallest(String S, int k) { String ans = "" ; int l = S.length(); if ((l & (l - 1 )) != 0 ) k += k; else k /= 2 ; if (k >= l) return "-1" ; Stack<Character> st = new Stack<Character>(); for ( int i = 0 ; i < l; i++) { while (!st.empty() && k > 0 && st.peek() > S.charAt(i)) { st.pop(); k--; } st.push(S.charAt(i)); } if (k > 0 ) while (k > 0 ) st.pop(); k--; while (!st.empty()) { ans = st.peek() + ans; st.pop(); } return ans; } // Driver Code public static void main(String args[]) { String S = "fooland" ; int K = 2 ; // Function Call System.out.println(lexicographicallySmallest(S, K)); } } // This code is contributed by Samim Hossain Mondal. |
Python3
# Python code to implement the approach # Function to find the lexicographically # smallest string def lexicographicallySmallest(S, k): ans = "" l = len (S) if (l&(l - 1 )): k + = k else : k / = 2 if (k > = l): return "-1" st = [] for i in range (l): while ( len (st) and k > 0 and st[ len (st) - 1 ] > S[i]): st.pop() k = k - 1 st.append(S[i]) if (k > 0 ): while (k > 0 ): k = k - 1 st.pop() while ( len (st)): ans = st[ len (st) - 1 ] + ans st.pop() return ans # Driver Code S = "fooland" K = 2 # Function Call print (lexicographicallySmallest(S,K)) # This code is contributed by Pushpesh Raj. |
C#
// C# code to implement the approach using System; using System.Collections; using System.Collections.Generic; public class GFG { // Function to find the lexicographically // smallest string public static string lexicographicallySmallest( string S, int k) { string ans = "" ; int l = S.Length; if ((l & (l - 1)) != 0) k += k; else k /= 2; if (k >= l) return "-1" ; Stack st = new Stack(); for ( int i = 0; i < l; i++) { while (st.Count != 0 && k > 0 && ( char )st.Peek() > S[i]) { st.Pop(); k--; } st.Push(S[i]); } if (k > 0) while (k > 0) st.Pop(); k--; while (st.Count != 0) { ans = st.Peek() + ans; st.Pop(); } return ans; } static public void Main() { // Code string S = "fooland" ; int K = 2; // Function call Console.WriteLine(lexicographicallySmallest(S, K)); } } // This code is contributed by lokeshmvs21. |
Javascript
// Javascript code to implement the approach // Function to find the lexicographically // smallest string function lexicographicallySmallest( S, k) { let ans = "" ; let l = S.length; if (l & (l - 1) !=0) k += k; else k /= 2; if (k >= l) return "-1" ; let st=[]; for (let i = 0; i < l; i++) { while ( st.length!=0 && k > 0 && st[st.length-1] > S[i]) { st.pop(); k--; } st.push(S[i]); } if (k > 0) while (k--) st.pop(); while (st.length!=0) { ans = st[st.length-1] + ans; st.pop(); } return ans; } // Driver Code let S = "fooland" ; let K = 2; // Function Call console.log(lexicographicallySmallest(S, K)); // This code is contributed by garg28harsh. |
and
Time Complexity: O(N + K), for traversal of every element of the string and inside the loop we traverse at most K times for the removal of strings from the stack so overall time is O(N + K).
Auxiliary Space: O(N), For storing characters in the stack.
Please Login to comment...