【数据结构-栈】【位运算优化】力扣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,代表这个栈为空。

相关推荐
Wx120不知道取啥名15 分钟前
C语言之长整型有符号数与短整型有符号数转换
c语言·开发语言·单片机·mcu·算法·1024程序员节
Iareges44 分钟前
美团2025校招 广告算法工程师 面经
算法·面试·求职招聘·笔试·秋招
IT规划师2 小时前
数据结构 - 散列表,三探之代码实现
数据结构·散列表·哈希表
堇舟2 小时前
斯皮尔曼相关(Spearman correlation)系数
人工智能·算法·机器学习
西几3 小时前
代码训练营 day48|LeetCode 300,LeetCode 674,LeetCode 718
c++·算法·leetcode
武子康3 小时前
大数据-187 Elasticsearch - ELK 家族 Logstash Filter 插件 使用详解
大数据·数据结构·elk·elasticsearch·搜索引擎·全文检索·1024程序员节
liuyang-neu3 小时前
力扣第420周赛 中等 3324. 出现在屏幕上的字符串序列
java·算法·leetcode
想做白天梦4 小时前
双向链表(数据结构与算法)
java·前端·算法
小卡皮巴拉4 小时前
【力扣刷题实战】相同的树
c语言·算法·leetcode·二叉树·递归
zyhomepage4 小时前
科技的成就(六十四)
开发语言·人工智能·科技·算法·内容运营