题目
给你一个包含若干星号 * 的字符串 s 。
在一步操作中,你可以:
选中 s 中的一个星号。
移除星号 左侧 最近的那个 非星号 字符,并移除该星号自身。
返回移除 所有 星号之后的字符串。
注意:
生成的输入保证总是可以执行题面中描述的操作。
可以证明结果字符串是唯一的。
一、代码实现
func removeStars(s string) string {
stack := []rune{}
for _, c := range s {
if c == '*' {
stack = stack[:len(stack)-1] // 遇到星号则弹出栈顶字符
} else {
stack = append(stack, c) // 非星号字符入栈
}
}
return string(stack) // 最终栈中元素即为结果
}
二、算法分析
1. 核心思路
- 栈结构特性:利用后进先出(LIFO)特性,遇到星号时弹出最近的非星号字符
- 遍历优化:只需一次线性扫描,时间复杂度为 O(n)
2. 关键步骤
- 字符入栈:遍历字符串时将所有非星号字符压入栈中
- 星号处理:遇到星号时弹出栈顶元素(无需判空,题目保证输入合法)
- 结果生成:将栈内剩余字符拼接为最终字符串
3. 复杂度
指标 | 值 | 说明 |
---|---|---|
时间复杂度 | O(n) | 单次遍历所有字符 |
空间复杂度 | O(n) | 栈存储最坏情况保存全部字符 |
三、图解示例
四、边界条件与扩展
1. 特殊场景验证
- 全星号场景:
"*****"
→ 返回空字符串(题目保证输入合法) - 连续星号:
"abc***"
→ 处理为""
(每次星号弹出前序字符) - 无星号:
"abcd"
→ 原样输出
2. 多语言实现
# Python实现(列表模拟栈)
def removeStars(s: str) -> str:
stack = []
for c in s:
if c == '*':
stack.pop() # 直接弹出无需判空
else:
stack.append(c)
return ''.join(stack)
// Java高效实现(StringBuilder模拟栈)
public String removeStars(String s) {
StringBuilder sb = new StringBuilder();
for (char c : s.toCharArray()) {
if (c == '*') {
sb.deleteCharAt(sb.length()-1); // 删除末尾字符
} else {
sb.append(c);
}
}
return sb.toString();
}
3. 算法对比
方法 | 时间复杂度 | 空间复杂度 | 优势 |
---|---|---|---|
栈模拟法 | O(n) | O(n) | 逻辑清晰,代码简洁 |
数组索引法 | O(n) | O(1) | 原地修改节省内存 |
递归回溯 | O(2^n) | O(n) | 仅适用于极小数据量 |
五、总结与扩展
1. 核心创新点
- 极简栈操作:仅需 5 行代码实现核心逻辑
- 空间复用优化:Go语言切片特性实现高效内存管理
2. 数学证明
设字符串长度为 n,星号数量为 k,则最终字符串长度为 n-2k(每个星号删除两个字符)
3. 扩展应用
- 文本编辑器撤销操作:类似栈的最近操作回退
- 括号匹配问题:通过栈结构处理嵌套关系
- 路径压缩:处理类似
../
的路径跳转逻辑