Medium
题目描述
给你一个字符串 s,它可能包含任意数量的 '*' 字符。你的任务是移除所有 '*' 字符。
当存在 '*' 时,执行以下操作:
- 删除最左边的
'*'和它左边字典序最小的非'*'字符。如果有多个最小字符,你可以删除其中任意一个。
返回移除所有 '*' 字符后字典序最小的结果字符串。
示例 1:
输入:s = "aaba*"
输出:"aab"
解释:我们应该删除一个 'a' 字符和 '*'。如果我们选择 s[3],s 变成字典序最小的。
示例 2:
输入:s = "abc"
输出:"abc"
解释:字符串中没有 '*'。
提示:
1 <= s.length <= 10^5s只包含小写英文字母和'*'- 输入保证可以删除所有
'*'字符
解题思路
这道题的核心思想是贪心算法。我们需要处理每个星号时,删除它左边字典序最小的字符,以确保最终结果字典序最小。
解题思路:
栈 + 哈希表方法(推荐):使用栈来维护当前字符,用哈希表记录每个字符的索引位置。遇到星号时,找到当前栈中字典序最小的字符进行删除。
标记数组方法:遍历字符串,用布尔数组标记要删除的字符。遇到星号时,向左查找最小字符并标记删除。
优先队列方法:使用最小堆存储字符及其位置,遇到星号时从堆顶取最小字符删除。
详细分析:
- 关键在于理解"左边最小字符"的含义:不是位置最左的最小字符,而是值最小的字符
- 需要高效地找到并删除指定字符,栈结构配合哈希表最为合适
- 最终构造结果时,保持原有的相对顺序
核心思想是维护一个动态的字符集合,能够快速找到最小字符并删除。
代码实现
class Solution {
public:
string clearStars(string s) {
vector<char> stk;
unordered_map<char, vector<int>> charIndices;
for (int i = 0; i < s.length(); i++) {
if (s[i] == '*') {
// 找到栈中最小的字符
char minChar = 'z' + 1;
for (auto& p : charIndices) {
if (!p.second.empty() && p.first < minChar) {
minChar = p.first;
}
}
// 删除最小字符的最后一个出现位置
if (minChar <= 'z') {
int idx = charIndices[minChar].back();
charIndices[minChar].pop_back();
if (charIndices[minChar].empty()) {
charIndices.erase(minChar);
}
stk[idx] = 0; // 标记为删除
}
} else {
charIndices[s[i]].push_back(stk.size());
stk.push_back(s[i]);
}
}
string result;
for (char c : stk) {
if (c != 0) {
result += c;
}
}
return result;
}
};
class Solution:
def clearStars(self, s: str) -> str:
stk = []
char_indices = {}
for i, c in enumerate(s):
if c == '*':
# 找到栈中最小的字符
if char_indices:
min_char = min(char_indices.keys())
idx = char_indices[min_char].pop()
if not char_indices[min_char]:
del char_indices[min_char]
stk[idx] = None # 标记为删除
else:
if c not in char_indices:
char_indices[c] = []
char_indices[c].append(len(stk))
stk.append(c)
return ''.join(c for c in stk if c is not None)
public class Solution {
public string ClearStars(string s) {
List<char?> stk = new List<char?>();
Dictionary<char, List<int>> charIndices = new Dictionary<char, List<int>>();
for (int i = 0; i < s.Length; i++) {
if (s[i] == '*') {
// 找到栈中最小的字符
if (charIndices.Count > 0) {
char minChar = charIndices.Keys.Min();
int idx = charIndices[minChar].Last();
charIndices[minChar].RemoveAt(charIndices[minChar].Count - 1);
if (charIndices[minChar].Count == 0) {
charIndices.Remove(minChar);
}
stk[idx] = null; // 标记为删除
}
} else {
if (!charIndices.ContainsKey(s[i])) {
charIndices[s[i]] = new List<int>();
}
charIndices[s[i]].Add(stk.Count);
stk.Add(s[i]);
}
}
return string.Concat(stk.Where(c => c.HasValue).Select(c => c.Value));
}
}
var clearStars = function(s) {
const stk = [];
const charIndices = new Map();
for (let i = 0; i < s.length; i++) {
if (s[i]
复杂度分析
| 复杂度类型 | 复杂度 | 说明 |
|---|---|---|
| 时间复杂度 | O(n × 26) = O(n) | n为字符串长度,每次查找最小字符最多遍历26个字母 |
| 空间复杂度 | O(n) | 栈和哈希表的存储空间 |