力扣第316与1081题 不同字符的最小子序列 C++ Java Python
目录
题目
中等
相关标签
提示
给你一个字符串 s
,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的
字典序
最小(要求不能打乱其他字符的相对位置)。
示例 1:
s = "bcabc"
:
"abc"
示例 2:
s = "cbacdcbc"
"acdb"
提示:
1 <= s.length <= 104
s
由小写英文字母组成
注意:该题与 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
添加到栈中,并标记为已访问。将栈中字符逆序输出,构成结果字符串。
觉得有用的话可以点点赞,支持一下。
如果愿意的话关注一下。会对你有更多的帮助。
每天都会不定时更新哦 >人< 。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)