【数据结构-栈】【位运算优化】力扣3170. 删除星号以后字典序最小的字符串

给你一个字符串 s 。它可能包含任意数量的 '' 字符。你的任务是删除所有的 '' 字符。

当字符串还存在至少一个 '*' 字符时,你可以执行以下操作:

删除最左边的 '' 字符,同时删除该星号字符左边一个字典序 最小 的字符。如果有多个字典序最小的字符,你可以删除它们中的任意一个。
请你返回删除所有 '
' 字符以后,剩余字符连接而成的

字典序最小

的字符串。

示例 1:

输入:s = "aaba*"

输出:"aab"

解释:

删除 '*' 号和它左边的其中一个 'a' 字符。如果我们选择删除 s[3] ,s 字典序最小。

示例 2:

输入:s = "abc"

输出:"abc"

解释:

字符串中没有 '*' 字符。

法一

cpp 复制代码
class Solution {
public:
    string clearStars(string s) {
        int n = s.size();
        stack<int> st[26];
        for(int i = 0; i < n; i++){
            if(s[i] != '*'){
                st[s[i] - 'a'].push(i);
            }
            else{
                for(auto &p : st){
                    if(!p.empty()){
                        s[p.top()] = '*';
                        p.pop();
                        break;
                    }
                }
            }
        }
        s.erase(remove(s.begin(),s.end(),'*'), s.end());
        return s;
    }
};

时间复杂度 :O(n∣Σ∣),其中 n 是 s 的长度,∣Σ∣ 为字符集合的大小,本题字符均为小写字母,所以 ∣Σ∣=26。
空间复杂度:O(n+∣Σ∣)。

这道题我们首先建立一个大小为26的栈数组,每个st[i]代表一个栈。我们按顺序遍历字符串,在遍历过程中,如果字符不为*,那么就在栈数组对应的栈推入这个字符的位置。比如说字符为a在i=0的位置,那么就是st[0] = {0}。

如果字符是*,那么我们就循环栈数组,栈数组会按字典序从小到大进行查询,优先删除字典序最小的字符。我们查找到字典序最小的字符所处的栈后,栈顶的元素代表这当前最靠右的字符的位置,我们在字符串s中将这个字符 s[p.top()] = '*';设为星号,代表这个字符已经被删除。然后执行完后,该栈就要弹出栈顶的元素的位置,因为他已经被删除不存在。一旦找到一个不为空的栈,就break,停止遍历栈数组。

最后 s.erase(remove(s.begin(), s.end(), '*'), s.end());,举个例子:

remove 会将字符串变为 "abcdef**",并返回一个指向第一个 '' 的位置的迭代器。
erase 会删除这两个 '
',最终 s 变为 "abcdef"。

位运算优化

cpp 复制代码
class Solution {
public:
    string clearStars(string s) {
        int n = s.size(), mask = 0;
        stack<int> st[26];
        for(int i = 0; i < n; i++){
            if(s[i] != '*'){
                st[s[i] - 'a'].push(i);
                mask |= 1<<(s[i]-'a');
            }
            else{
                int k = __builtin_ctz(mask);
                auto& p = st[k];
                s[p.top()] = '*';
                p.pop();
                if(p.empty()){
                    mask ^= 1 << k;
                }
            }
        }
        s.erase(remove(s.begin(),s.end(),'*'), s.end());
        return s;
    }
};

时间复杂度 :O(n+∣Σ∣),其中 n 是 s 的长度,∣Σ∣ 为字符集合的大小,本题字符均为小写字母,所以 ∣Σ∣=26。
空间复杂度:O(n+∣Σ∣)。

位运算优化的地方在我们之前通过遍历栈数组来查找最小字典序的栈是哪个,我们可以使用一个二进制数mask通过0和1来记录每个栈是否不为空。在循环字符串s的过程中,字符不为星号,则让mask对应位置变为1,说明这个字母存在。

如果遍历s的过程中字符为星号,则定义一个整数k,调用内置函数__builtin_ctz(mask)来返回mask中最右侧的1的右边有多少个0。k就是我们需要查找的栈数组中的栈的位置。然后最后,如果栈推出元素后为空,那么就通过异或1来将mask中的1置为0,代表这个栈为空。

相关推荐
科大饭桶29 分钟前
C++入门自学Day14-- Stack和Queue的自实现(适配器)
c语言·开发语言·数据结构·c++·容器
tt5555555555551 小时前
字符串与算法题详解:最长回文子串、IP 地址转换、字符串排序、蛇形矩阵与字符串加密
c++·算法·矩阵
元亓亓亓1 小时前
LeetCode热题100--101. 对称二叉树--简单
算法·leetcode·职场和发展
躲在云朵里`1 小时前
深入理解数据结构:从数组、链表到B树家族
数据结构·b树
不会学习?2 小时前
算法03 归并分治
算法
NuyoahC3 小时前
笔试——Day43
c++·算法·笔试
2301_821919923 小时前
决策树8.19
算法·决策树·机器学习
秋难降3 小时前
别再用暴力排序了!大小顶堆让「取极值」效率飙升至 O (log n)
python·算法·排序算法
学行库小秘4 小时前
基于门控循环单元的数据回归预测 GRU
人工智能·深度学习·神经网络·算法·回归·gru
_meow_4 小时前
数学建模 15 逻辑回归与随机森林
算法·数学建模·逻辑回归