目录
题目
中等
相关标签
提示
给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的
字典序
最小(要求不能打乱其他字符的相对位置)。
示例 1:
输入:s = "bcabc"输出:"abc"
示例 2:
输入:s = "cbacdcbc"输出:"acdb"
提示:
1 <= s.length <= 104s由小写英文字母组成
注意:该题与 1081 . - 力扣(LeetCode) 相同
思路和解题方法
- 使用栈
stk存储结果字符串的字符,使用集合visited记录栈中已经包含的字符。- 统计每个字符出现的次数,并遍历原始字符串
s。- 对于每个字符
ch:
- 减少其出现次数。
- 如果栈中已经包含了字符
ch,则直接跳过。- 如果栈顶元素大于当前字符
ch,且后面还会出现,则将栈顶元素移除。- 将字符
ch添加到栈中,并标记为已访问。- 将栈中字符逆序输出,构成结果字符串。
复杂度:
-
时间复杂度:O(n)
- 遍历字符串的时间复杂度为 O(n),其中 n 是字符串的长度。
-
空间复杂度:O(n)
- 使用了栈和集合来存储结果字符和已访问字符,以及一个额外的数组来统计字符出现次数,因此空间复杂度为 O(n)。
c++ 代码
#include <string>
#include <stack>
#include <unordered_set>
#include <vector>
using namespace std;
class Solution {
public:
string smallestSubsequence(string s) {
stack<char> stk; // 用于存储结果字符串的栈
unordered_set<char> visited; // 用于记录栈中已经包含的字符
vector<int> count(26, 0); // 记录每个字符出现的次数
// 统计每个字符出现的次数
for (char ch : s) {
count[ch - 'a']++;
}
for (char ch : s) {
// 对于每个字符ch,首先减少其出现次数
count[ch - 'a']--;
// 如果栈中已经包含了字符ch,则直接跳过
if (visited.count(ch)) {
continue;
}
// 如果栈顶元素大于当前字符ch,且后面还会出现,则将栈顶元素移除
while (!stk.empty() && stk.top() > ch && count[stk.top() - 'a'] > 0) {
visited.erase(stk.top());
stk.pop();
}
// 将字符ch添加到栈中,并标记为已访问
stk.push(ch);
visited.insert(ch);
}
// 将栈中字符逆序输出,构成结果字符串
string result;
while (!stk.empty()) {
result = stk.top() + result;
stk.pop();
}
return result;
}
};
Java 版本(仅供参考)
import java.util.*;
class Solution {
public String smallestSubsequence(String s) {
Stack<Character> stk = new Stack<>(); // 用于存储结果字符串的栈
Set<Character> visited = new HashSet<>(); // 用于记录栈中已经包含的字符
int[] count = new int[26]; // 记录每个字符出现的次数
// 统计每个字符出现的次数
for (char ch : s.toCharArray()) {
count[ch - 'a']++;
}
for (char ch : s.toCharArray()) {
// 对于每个字符ch,首先减少其出现次数
count[ch - 'a']--;
// 如果栈中已经包含了字符ch,则直接跳过
if (visited.contains(ch)) {
continue;
}
// 如果栈顶元素大于当前字符ch,且后面还会出现,则将栈顶元素移除
while (!stk.isEmpty() && stk.peek() > ch && count[stk.peek() - 'a'] > 0) {
visited.remove(stk.peek());
stk.pop();
}
// 将字符ch添加到栈中,并标记为已访问
stk.push(ch);
visited.add(ch);
}
// 将栈中字符逆序输出,构成结果字符串
StringBuilder result = new StringBuilder();
while (!stk.isEmpty()) {
result.insert(0, stk.pop());
}
return result.toString();
}
}
Python 版本(仅供参考)
class Solution:
def smallestSubsequence(self, s: str) -> str:
stk = [] # 用于存储结果字符串的栈
visited = set() # 用于记录栈中已经包含的字符
count = [0] * 26 # 记录每个字符出现的次数
# 统计每个字符出现的次数
for ch in s:
count[ord(ch) - ord('a')] += 1
for ch in s:
# 对于每个字符ch,首先减少其出现次数
count[ord(ch) - ord('a')] -= 1
# 如果栈中已经包含了字符ch,则直接跳过
if ch in visited:
continue
# 如果栈顶元素大于当前字符ch,且后面还会出现,则将栈顶元素移除
while stk and stk[-1] > ch and count[ord(stk[-1]) - ord('a')] > 0:
visited.remove(stk[-1])
stk.pop()
# 将字符ch添加到栈中,并标记为已访问
stk.append(ch)
visited.add(ch)
# 将栈中字符逆序输出,构成结果字符串
return ''.join(stk)
代码细节
在 C++ 版本中,
unordered_set是用于记录栈中已经包含的字符,而vector<int> count(26, 0)是用于统计每个字符出现的次数。C++ 中的
stk为stack<char>类型,用于存储结果字符串的字符;visited为unordered_set<char>类型,用于记录栈中已经包含的字符;count为vector<int>类型,用于记录每个字符出现的次数。在 Java 版本中,
Stack<Character>是用于存储结果字符串的栈,Set<Character>是用于记录栈中已经包含的字符,int[] count是用于记录每个字符出现的次数。Python 版本中使用列表
stk存储结果字符串的字符,集合visited记录栈中已经包含的字符,count为列表,用于记录每个字符出现的次数。在遍历字符串时,对于每个字符
ch,首先减少其出现次数count[ch - 'a']--。如果栈中已经包含了字符
ch,则直接跳过当前字符。如果栈顶元素大于当前字符
ch,且后面还会出现,则将栈顶元素移除。将字符
ch添加到栈中,并标记为已访问。将栈中字符逆序输出,构成结果字符串。
觉得有用的话可以点点赞,支持一下。
如果愿意的话关注一下。会对你有更多的帮助。
每天都会不定时更新哦 >人< 。

本文介绍了解决字符串去重问题的方法,利用栈和集合数据结构,保证字典序最小,同时分析了时间复杂度为O(n)和空间复杂度为O(n)的算法,并提供了C++,Java和Python三种编程语言的代码实现。

6654

被折叠的 条评论
为什么被折叠?



