Open In App

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:

Code:

Below is the implementation of the above approach.




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




# 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# 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 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:

Below is the implementation of the above approach.




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




# 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# 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 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.


Article Tags :