DEV Community

Cover image for ๐Ÿงฉ Guide to Solving "Lexicographically Minimum String After Removing Stars" LeetCode 3170 (C++ | JavaScript | Python)
Om Shree
Om Shree

Posted on

๐Ÿงฉ Guide to Solving "Lexicographically Minimum String After Removing Stars" LeetCode 3170 (C++ | JavaScript | Python)

Hey, tech explorers! ๐ŸŒŸ Today, letโ€™s decode a delightful greedy string manipulation problem โ€” LeetCode 3170: Lexicographically Minimum String After Removing Stars. We'll walk through a structured approach and implement it step by step in C++, JavaScript, and Python. Letโ€™s go! ๐Ÿš€


๐Ÿ“œ Problem Overview

Youโ€™re given a string s containing lowercase letters and asterisks *.

You must repeatedly perform this operation until no * is left:

  1. Remove the leftmost *.
  2. Remove the smallest non-* character to its left. If there are multiple smallest characters, you can choose any.

๐Ÿ“ Goal: Return the lexicographically smallest string after all * and their associated characters have been deleted.


๐Ÿง  Intuition & Strategy

This problem is all about greedy decision-making. At every step, you must:

  • Process characters left to right.
  • For every *, find the smallest character to its left and remove it.
  • Make sure you handle characters efficiently โ€” especially for large strings (1 <= s.length <= 10โต).

We use:

  • A min-heap to track the smallest character encountered so far.
  • An index tracker for each character (a to z) to know their positions in the string.
  • A marking technique (using !) to flag removed characters.
  • A final pass to build the answer string.

โš™๏ธ C++ Code (Efficient & Clean)

class Solution {
public:
    string clearStars(string s) {
        priority_queue<char, vector<char>, greater<char>> pq;
        vector<vector<int>> indices(26);

        for (int i = 0; i < s.size(); i++) {
            if (s[i] == '*') {
                char ch = pq.top();
                s[indices[ch - 'a'].back()] = '!';  // mark as deleted
                indices[ch - 'a'].pop_back();
                if (indices[ch - 'a'].empty()) {
                    pq.pop();  // remove from heap if no more left
                }
            } else {
                if (indices[s[i] - 'a'].empty()) {
                    pq.push(s[i]);  // new character, push into heap
                }
                indices[s[i] - 'a'].push_back(i);
            }
        }

        string res = "";
        for (char c : s) {
            if (c >= 'a') res += c;
        }
        return res;
    }
};
Enter fullscreen mode Exit fullscreen mode

๐ŸŒ JavaScript Version

var clearStars = function(s) {
    const indices = Array.from({ length: 26 }, () => []);
    const arr = s.split('');
    const pq = [];

    const pushHeap = (ch) => {
        if (!pq.includes(ch)) {
            pq.push(ch);
            pq.sort();  // simple sort-based heap
        }
    };

    for (let i = 0; i < arr.length; i++) {
        if (arr[i] === '*') {
            while (pq.length && indices[pq[0].charCodeAt(0) - 97].length === 0) {
                pq.shift();  // clean up dead entries
            }
            const smallest = pq[0];
            const idx = indices[smallest.charCodeAt(0) - 97].pop();
            arr[idx] = '!';

            if (indices[smallest.charCodeAt(0) - 97].length === 0) {
                pq.shift();
            }
        } else {
            const code = arr[i].charCodeAt(0) - 97;
            if (indices[code].length === 0) pushHeap(arr[i]);
            indices[code].push(i);
        }
    }

    return arr.filter(c => c >= 'a').join('');
};
Enter fullscreen mode Exit fullscreen mode

๐Ÿ Python Version

import heapq
from collections import defaultdict

class Solution:
    def clearStars(self, s: str) -> str:
        s = list(s)
        pq = []
        indices = defaultdict(list)

        for i, ch in enumerate(s):
            if ch == '*':
                while pq and not indices[pq[0]]:
                    heapq.heappop(pq)

                smallest = pq[0]
                idx = indices[smallest].pop()
                s[idx] = '!'  # mark as deleted

                if not indices[smallest]:
                    heapq.heappop(pq)
            else:
                if not indices[ch]:
                    heapq.heappush(pq, ch)
                indices[ch].append(i)

        return ''.join(c for c in s if c >= 'a')
Enter fullscreen mode Exit fullscreen mode

๐Ÿงช Test Cases

Input: "aaba*"
Output: "aab"
Explanation: Remove the last 'a' before the '*' for smallest result.

Input: "abc"
Output: "abc"
Explanation: No stars, nothing to remove.

Input: "zz*yy*aa*"
Output: "zya"
Explanation: Always remove the smallest character before each '*'.

Input: "aaab*bbc*"
Output: "aabb"
Enter fullscreen mode Exit fullscreen mode

๐Ÿงฎ Time & Space Complexity

Time Complexity: O(n log k) where k โ‰ค 26  // Heap operations over 26 letters
Space Complexity: O(n)                   // Position tracking and character marking
Enter fullscreen mode Exit fullscreen mode

โœจ Wrap Up

This problem is a wonderful exercise in greedy thinking and priority queues. ๐Ÿ’ก
By carefully tracking the smallest deletable characters and handling each star in order, weโ€™re able to produce the lexicographically smallest result.

If you found this helpful, drop a โค๏ธ, leave a comment, or follow for more clean walkthroughs!

Happy coding, explorers! ๐Ÿš€๐Ÿ’ป


Top comments (2)

Collapse
 
thedeepseeker profile image
Anna kowoski

Great Explanation, was stuck on this problem for hours

Collapse
 
om_shree_0709 profile image
Om Shree

Understandable, took me a while to figure it out myself.

Some comments may only be visible to logged-in visitors. Sign in to view all comments.