去除重复字母
难度:
标签:
题目描述
给你一个字符串 s
,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的字典序最小(要求不能打乱其他字符的相对位置)。
示例 1:
输入:s = "bcabc"
输出:
"abc"
示例 2:
输入:s = "cbacdcbc"
输出:"acdb"
提示:
1 <= s.length <= 104
s
由小写英文字母组成
注意:该题与 1081 https://leetcode-cn.com/problems/smallest-subsequence-of-distinct-characters 相同
代码结果
运行时间: 24 ms, 内存: 0.0 MB
// 使用Java Stream的解法
// 思路:
// 1. 计算每个字符最后出现的位置。
// 2. 通过字符串流过滤掉已经在结果字符串中的字符。
// 3. 通过reduce方法合并结果字符串。
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.Map;
import java.util.HashMap;
public class Solution {
public String removeDuplicateLetters(String s) {
// 计算每个字符最后出现的位置
Map<Character, Integer> lastIndex = IntStream.range(0, s.length())
.boxed()
.collect(Collectors.toMap(i -> s.charAt(i), i -> i, (a, b) -> b));
// 使用StringBuilder保存结果字符串
StringBuilder result = new StringBuilder();
s.chars().distinct().forEach(c -> {
char ch = (char) c;
while (result.length() > 0 && result.charAt(result.length() - 1) > ch && lastIndex.get(result.charAt(result.length() - 1)) > s.indexOf(ch)) {
result.deleteCharAt(result.length() - 1);
}
result.append(ch);
});
return result.toString();
}
}
解释
方法:
该题解使用了单调栈的思路。具体来说,遍历字符串 s 中的每个字符,如果当前字符已经在栈中,则直接跳过;否则,将栈顶元素与当前字符比较,如果栈顶元素大于当前字符且栈顶元素在后面还会出现,则弹出栈顶元素,直到栈为空或栈顶元素小于等于当前字符。然后将当前字符压入栈中。最后将栈中元素拼接成字符串作为结果返回。这样可以保证结果字符串的字典序最小。
时间复杂度:
O(n)
空间复杂度:
O(n)
代码细节讲解
🦆
在题解中提到的`单调栈`是如何确保生成的字符串字典序最小的?
▷🦆
如果输入字符串`s`中包含所有26个英文字母,单调栈的最大可能高度是多少?
▷🦆
题解中提到,跳过栈中已有的字符是基于什么逻辑?为什么不需要再次考虑这些字符?
▷🦆
在弹出栈顶元素的条件中,需要检查栈顶元素在后面是否还会出现,这是如何通过`cnt`哈希表实现的?
▷