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”.
Naïve 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.
Code:
Below is the implementation of the above approach.
C++
#include <bits/stdc++.h>
using namespace std;
int countSetBits( int n)
{
int count = 0;
while (n) {
count += n & 1;
n >>= 1;
}
return count;
}
string lexicographicallySmallest(string str, int k)
{
int n = str.size();
if (countSetBits(n) == 1)
k /= 2;
else
k *= 2;
if (k >= n)
return "-1" ;
int a[n], i, j;
for (i = 0; i < n; i++)
a[i] = 1;
for (i = 0; i < n;) {
int start = i;
int index = start;
int end = min(start + k, n - 1);
char minn = str[start];
for (j = start + 1; j <= end; j++) {
if (str[j] < minn) {
minn = str[j];
index = j;
}
}
for (j = index - 1; j >= start and k != 0; j--) {
a[j] = 0;
k--;
}
i = index + 1;
}
if (k) {
for (i = n - 1; i >= 0 and k != 0; i--) {
if (a[i]) {
a[i] = 0;
k--;
}
}
}
string res = "" ;
for (i = 0; i < n; i++) {
if (a[i]) {
res += str[i];
}
}
return res;
}
int main()
{
string S = "fooland" ;
int K = 2;
cout << lexicographicallySmallest(S, K) << endl;
return 0;
}
|
Java
import java.io.*;
class GFG {
static public int countSetBits( int n)
{
int count = 0 ;
while (n > 0 ) {
count += n & 1 ;
n >>= 1 ;
}
return count;
}
static public String
lexicographicallySmallest(String str, int k)
{
int n = str.length();
if (countSetBits(n) == 1 )
k /= 2 ;
else
k *= 2 ;
if (k >= n)
return "-1" ;
int [] a = new int [n];
int i, j;
for (i = 0 ; i < n; i++)
a[i] = 1 ;
for (i = 0 ; i < n;) {
int start = i;
int index = start;
int end = Math.min(start + k, n - 1 );
char minn = str.charAt(start);
for (j = start + 1 ; j <= end; j++) {
if (str.charAt(j) < minn) {
minn = str.charAt(j);
index = j;
}
}
for (j = index - 1 ; j >= start && k != 0 ; j--) {
a[j] = 0 ;
k--;
}
i = index + 1 ;
}
if (k != 0 ) {
for (i = n - 1 ; i >= 0 && k != 0 ; i--) {
if (a[i] != 0 ) {
a[i] = 0 ;
k--;
}
}
}
String res = "" ;
for (i = 0 ; i < n; i++) {
if (a[i] != 0 ) {
res += str.charAt(i);
}
}
return res;
}
public static void main(String[] args)
{
String S = "fooland" ;
int K = 2 ;
System.out.println(lexicographicallySmallest(S, K));
}
}
|
Python
def countSetBits(n):
count = 0
while n:
count + = n & 1
n >> = 1
return count
def lexicographicallySmallest( str , k):
n = len ( str )
if countSetBits(n) = = 1 :
k / / = 2
else :
k * = 2
if k > = n:
return "-1"
a = [ 1 ] * n
i = 0
while i < n:
start = i
index = start
end = min (start + k, n - 1 )
minn = str [start]
for j in range (start + 1 , end + 1 ):
if str [j] < minn:
minn = str [j]
index = j
for j in range (index - 1 , start - 1 , - 1 ):
if k ! = 0 :
a[j] = 0
k - = 1
i = index + 1
if k:
for i in range (n - 1 , - 1 , - 1 ):
if a[i]:
a[i] = 0
k - = 1
res = ""
for i in range (n):
if a[i]:
res + = str [i]
return res
if __name__ = = '__main__' :
S = "fooland"
K = 2
print (lexicographicallySmallest(S, K))
|
C#
using System;
public class GFG {
static public int countSetBits( int n)
{
int count = 0;
while (n > 0) {
count += n & 1;
n >>= 1;
}
return count;
}
static public string
lexicographicallySmallest( string str, int k)
{
int n = str.Length;
if (countSetBits(n) == 1)
k /= 2;
else
k *= 2;
if (k >= n)
return "-1" ;
int [] a = new int [n];
int i, j;
for (i = 0; i < n; i++)
a[i] = 1;
for (i = 0; i < n;) {
int start = i;
int index = start;
int end = Math.Min(start + k, n - 1);
char minn = str[start];
for (j = start + 1; j <= end; j++) {
if (str[j] < minn) {
minn = str[j];
index = j;
}
}
for (j = index - 1; j >= start && k != 0; j--) {
a[j] = 0;
k--;
}
i = index + 1;
}
if (k != 0) {
for (i = n - 1; i >= 0 && k != 0; i--) {
if (a[i] != 0) {
a[i] = 0;
k--;
}
}
}
string res = "" ;
for (i = 0; i < n; i++) {
if (a[i] != 0) {
res += str[i];
}
}
return res;
}
static public void Main()
{
string S = "fooland" ;
int K = 2;
Console.WriteLine(lexicographicallySmallest(S, K));
}
}
|
Javascript
const countSetBits = (n) => {
let count = 0;
while (n) {
count += n & 1;
n >>= 1;
}
return count;
}
const lexicographicallySmallest = (str, k) => {
let n = str.length;
if (countSetBits(n) == 1)
k = parseInt(k / 2);
else
k *= 2;
if (k >= n)
return "-1" ;
let a = new Array(n).fill(0), i, j;
for (i = 0; i < n; i++)
a[i] = 1;
for (i = 0; i < n;) {
let start = i;
let index = start;
let end = Math.min(start + k, n - 1);
let minn = str[start];
for (j = start + 1; j <= end; j++) {
if (str[j] < minn) {
minn = str[j];
index = j;
}
}
for (j = index - 1; j >= start && k != 0; j--) {
a[j] = 0;
k--;
}
i = index + 1;
}
if (k) {
for (i = n - 1; i >= 0 && k != 0; i--) {
if (a[i]) {
a[i] = 0;
k--;
}
}
}
let res = "" ;
for (i = 0; i < n; i++) {
if (a[i]) {
res += str[i];
}
}
return res;
}
let S = "fooland" ;
let K = 2;
console.log(lexicographicallySmallest(S, K));
|
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++
#include <bits/stdc++.h>
using namespace std;
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();
st.pop();
}
reverse(ans.begin(),ans.end());
return ans;
}
int main()
{
string S = "fooland" ;
int K = 2;
cout << lexicographicallySmallest(S, K);
return 0;
}
|
Java
import java.util.*;
public class GFG {
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;
}
public static void main(String args[])
{
String S = "fooland" ;
int K = 2 ;
System.out.println(lexicographicallySmallest(S, K));
}
}
|
Python3
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
S = "fooland"
K = 2
print (lexicographicallySmallest(S,K))
|
C#
using System;
using System.Collections;
using System.Collections.Generic;
public class GFG {
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()
{
string S = "fooland" ;
int K = 2;
Console.WriteLine(lexicographicallySmallest(S, K));
}
}
|
Javascript
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;
}
let S = "fooland" ;
let K = 2;
console.log(lexicographicallySmallest(S, K));
|
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.
Last Updated :
16 Oct, 2023
Like Article
Save Article
Share your thoughts in the comments
Please Login to comment...