Open In App

Lexicographically smallest String by removing exactly K characters

Improve
Improve
Like Article
Like
Save
Share
Report

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++




// 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


Output

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();
        st.pop();
    }
    reverse(ans.begin(),ans.end());
    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.


Output

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.



Last Updated : 16 Oct, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads