介绍
标签:栈、贪心算法、字符串
316. 去除重复字母
难度 中等
316. 去除重复字母
https://leetcode-cn.com/problems/sort-list/
题目
给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的字典序最小(要求不能打乱其他字符的相对位置)。
注意:该题与 1081 https://leetcode-cn.com/problems/smallest-subsequence-of-distinct-characters 相同
示例 1:
输入:s = “bcabc”
输出:“abc”
示例 2:
输入:s = “cbacdcbc”
输出:“acdb”
提示:
- 1 <= s.length <= 104
- s 由小写英文字母组成
解题思路
这是官方上面的思路
用栈来存储最终返回的字符串,并维持字符串的最小字典序
每遇到一个字符,如果这个字符不存在于栈中,就需要将该字符压入栈中。
但在压入之前,需要先将之后还会出现,并且字典序比当前字符小的栈>顶字符移除,然后再将当前字符压入。
建议在理解之前去看那个PPT,官方题解
这个题目我是从402. 移掉K位数字来的
所以出栈的思路延续了上一题的
出栈有3个条件:
- 栈顶元素大于当前字母,确保字典序最小
- 栈顶元素还不是最后一次出现,如果已经是最后一个了,你再把他出栈了,那这个字母就不会出现在结果中了
- 判断当前字母是否已经在栈中,都在栈里面了,再入的话不就重复了?
代码
class Solution {
public String removeDuplicateLetters(String s) {
//所有字母的最远位置(为什么不是记录出现次数,因为还要初始化很麻烦,而且还可以省去自减的步骤)
int[] distance = new int[26];
//当前解集是否包含当前字母
int[] contains = new int[26];
for (int i = 0; i < s.length(); i++){
distance[s.charAt(i) - 'a'] = i;
}
//单调栈 也就是最后的解集
char[] stack = new char[26];
int index = -1;
for (int i = 0; i < s.length(); i++){
char c = s.charAt(i);
//出栈条件:栈顶元素大于当前字母,栈顶元素还不是最后一次出现,判断当前字母是否已经在栈中了
while (index >= 0 && stack[index]>= c && distance[stack[index] -'a'] >= i && contains[c -'a'] == 0)
{
//出栈
contains[stack[index] - 'a'] = 0;
index --;
}
//当前解集中不存在这个字母,则入栈
if(contains[c - 'a'] == 0)
{
stack[++index] = c;
contains[c - 'a'] = 1;
}
}
return new String(stack, 0, ++index);
}
}
结果展示
内存消耗是个玄学问题,相同的代码,过段时间交就不一样了