3170: Lexicographically-Minimum-String-After-Removing-Stars
Medium


table of contents

My initial solution was basically, we can sort all the letters in a priority queue in the order at which they should be getting removed from s if an asterisk was to appear.

Then, keeping like a bitmap of all the letters that still remain after one pass of the string, we can construct what the resulting string should look like after removing all * characters.

code

class Solution {
public:
    string clearStars(string s) {
        auto comparator = [&](auto first, auto second) {
            if (first.first != second.first) {
                return first.first > second.first;
            } else {
                return first.second < second.second;
            }
        };
        vector<bool> bitmap (s.size(), true);
        priority_queue<pair<char, int>, vector<pair<char, int>>, decltype(comparator)> pq(comparator);
        for (int i = 0; i < s.size(); ++i) {
            if (s[i] != '*') {
                pq.push({s[i], i});
            } else {
                bitmap[i] = false;
                bitmap[pq.top().second] = false;
                pq.pop();
            }
        }
        string ans = "";
        for (int i = 0; i < s.size(); ++i) {
            if (bitmap[i]) {
                ans += s[i];
            }
        }
        return ans;
    }
};

complexity

learnings

The other solution that I saw revolved around keeping 26 stacks (for each letter of the alphabet) and only popping from the smallest stack.

NOTE: wait… I do not need another bitmap array… I can just swap out removed letters in s with an asterisk…

class Solution {
public:
    string clearStars(string s) {
        vector<stack<int>> lastLetter(26);
        
        for (int i = 0; i < s.size(); ++i) {
            if (s[i] != '*') {
                lastLetter[s[i]-'a'].push(i);
            } else {
                for (int i = 0; i < 26; ++i) {
                    if (!lastLetter[i].empty()) {
                        s[lastLetter[i].top()] = '*';
                        lastLetter[i].pop();
                        break;
                    }
                }
            }
        }

        string ans = "";
        for (int i = 0; i < s.size(); ++i) {
            if (s[i] != '*') {
                ans += s[i];
            }
        }
        return ans;
    }
};

and an improved version of the original solution above (removing the bitmap array and just replacing the deleted letters in-place with an asterisk *):

class Solution {
public:
    string clearStars(string s) {
        auto comparator = [&](auto first, auto second) {
            if (first.first != second.first) {
                return first.first > second.first;
            } else {
                return first.second < second.second;
            }
        };
        priority_queue<pair<char, int>, vector<pair<char, int>>, decltype(comparator)> pq(comparator);
        for (int i = 0; i < s.size(); ++i) {
            if (s[i] != '*') {
                pq.push({s[i], i});
            } else {
                s[pq.top().second] = '*';
                pq.pop();
            }
        }
        string ans = "";
        for (int i = 0; i < s.size(); ++i) {
            if (s[i] != '*') {
                ans += s[i];
            }
        }
        return ans;
    }
};

time taken