githubEdit

19. Remove K Digits

βœ… GFG solution to the Remove K Digits problem: find the smallest possible number after removing k digits using greedy monotonic stack approach. πŸš€

The problem can be found at the following link: πŸ”— Question Linkarrow-up-right

🧩 Problem Description

Given a non-negative integer s represented as a string and an integer k, remove exactly k digits from the string so that the resulting number is the smallest possible, while maintaining the relative order of the remaining digits.

Note: The resulting number must not contain any leading zeros. If the resulting number is an empty string after the removal, return "0".

πŸ“˜ Examples

Example 1

Input: s = "4325043", k = 3
Output: "2043"
Explanation: Remove the three digits 4, 3, and 5 to form the new number "2043" 
which is smallest among all possible removals.

Example 2

Input: s = "765028321", k = 5
Output: "221"
Explanation: Remove the five digits 7, 6, 5, 8 and 3 to form the new number "0221". 
Since we are not supposed to keep leading 0s, we get "221".

πŸ”’ Constraints

  • $1 \le k \le |s| \le 10^6$

βœ… My Approach

The optimal solution uses a Greedy Monotonic Stack approach to build the smallest possible number:

Greedy Monotonic Stack Strategy

  1. Initialize Result String:

    • Use a string/stack to build the result digit by digit.

    • Maintain monotonic increasing property for optimal smallest number.

  2. Process Each Digit:

    • Iterate through each character in the input string.

    • While the result is not empty, k > 0, and the last digit in result is greater than current digit:

      • Remove the last digit from result (greedy removal of larger digit).

      • Decrement k.

  3. Handle Leading Zeros:

    • Only add digits to result if result is non-empty OR current digit is not '0'.

    • This ensures no leading zeros in final result.

  4. Remove Remaining Digits:

    • If k > 0 after processing all digits, remove k digits from the end of result.

    • These are the largest remaining digits at the end.

  5. Return Result:

    • If result is empty, return "0".

    • Otherwise, return the constructed result string.

πŸ“ Time and Auxiliary Space Complexity

  • Expected Time Complexity: O(n), where n is the length of the string. Each digit is processed at most twice - once when added and once when potentially removed, resulting in linear time complexity.

  • Expected Auxiliary Space Complexity: O(n), as we use a result string/stack to store the processed digits. In the worst case, all digits might be retained in the result.

πŸ§‘β€πŸ’» Code (C++)

chevron-right⚑ View Alternative Approaches with Code and Analysishashtag

πŸ“Š 2️⃣ Deque-Based Approach

πŸ’‘ Algorithm Steps:

  1. Use deque to maintain digits in monotonic increasing order.

  2. Remove larger digits from back when smaller digit arrives and k > 0.

  3. Skip leading zeros by checking if deque is empty before insertion.

  4. Remove remaining digits from back if k budget still remains.

πŸ“ Complexity Analysis:

  • Time: ⏱️ O(n) - Single pass through string

  • Auxiliary Space: πŸ’Ύ O(n) - Deque storage

βœ… Why This Approach?

  • Flexible data structure for both ends

  • Similar performance to string approach

  • Good for bidirectional operations

πŸ“Š 3️⃣ Vector-Based Approach

πŸ’‘ Algorithm Steps:

  1. Build result using vector for efficient operations.

  2. Maintain monotonic stack property using vector.

  3. Handle leading zeros and remaining removals.

  4. Convert vector to string at the end.

πŸ“ Complexity Analysis:

  • Time: ⏱️ O(n) - Linear traversal

  • Auxiliary Space: πŸ’Ύ O(n) - Vector storage

βœ… Why This Approach?

  • Fast random access if needed

  • Cache-friendly memory layout

  • Standard container familiarity

πŸ“Š 4️⃣ In-Place String Modification

πŸ’‘ Algorithm Steps:

  1. Use two pointers to modify string in-place.

  2. Write pointer tracks where to place next valid digit.

  3. Read pointer scans through original string.

  4. Minimize allocations by reusing input string.

πŸ“ Complexity Analysis:

  • Time: ⏱️ O(n) - Single pass with in-place modification

  • Auxiliary Space: πŸ’Ύ O(1) - No extra data structures

βœ… Why This Approach?

  • Most space-efficient solution

  • No additional memory allocation

  • Optimal for memory-constrained environments

πŸ†š πŸ” Comparison of Approaches

πŸš€ Approach

⏱️ Time Complexity

πŸ’Ύ Space Complexity

βœ… Pros

⚠️ Cons

πŸ”€ String Builder

🟒 O(n)

🟑 O(n)

πŸš€ Clean and readable

πŸ’Ύ Extra space for result

πŸ”„ Deque-Based

🟒 O(n)

🟑 O(n)

🎯 Flexible operations

πŸ“¦ Overhead of deque

πŸ“Š Vector-Based

🟒 O(n)

🟑 O(n)

⚑ Cache-friendly

πŸ”§ Conversion overhead

✏️ In-Place

🟒 O(n)

🟒 O(1)

πŸ’Ž Optimal space usage

πŸ”§ Modifies input

πŸ† Best Choice Recommendation

🎯 Scenario

πŸŽ–οΈ Recommended Approach

πŸ”₯ Performance Rating

πŸ… Clean code priority

πŸ₯‡ String Builder

β˜…β˜…β˜…β˜…β˜…

πŸ’Ύ Memory constraints

πŸ₯ˆ In-Place

β˜…β˜…β˜…β˜…β˜…

πŸ”§ Bidirectional needs

πŸ₯‰ Deque-Based

β˜…β˜…β˜…β˜…β˜†

🎯 General purpose

πŸ… Vector-Based

β˜…β˜…β˜…β˜…β˜†

β˜• Code (Java)

🐍 Code (Python)

🧠 Contribution and Support

For discussions, questions, or doubts related to this solution, feel free to connect on LinkedIn: πŸ“¬ Any Questions?arrow-up-right. Let's make this learning journey more collaborative!

⭐ If you find this helpful, please give this repository a star! ⭐


πŸ“Visitor Count

Visitor counter

Last updated