Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
一.题目
316. 去除重复字母 给你一个字符串
s,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的字典序最小(要求不能打乱其他字符的相对位置)。
示例 1:
输入: s = "bcabc"
输出: "abc"
示例 2:
输入: s = "cbacdcbc"
输出: "acdb"
提示:
1 <= s.length <= 104s由小写英文字母组成
二、思路分析:
老规矩,首先理解题目,题目的要求是字符串去重,结果需要保证为字符串中没有重复元素,不能打乱其他字符的相对位置,返回结果的字典序最小。
要求1,要求2很好实现,我们可以用JS的函数indexOf和lastindexOf实现求解,但是这种方法只能保证要求1和要求2符合,要求3就不能够实现了,我们需要找到新的方法解决它。
所以我们需要利用到单调栈的思路,但是需要改变一下策略:我们利用到了单调栈的基本框架,但是出栈的条件需要改为:我们先记录下每个字符出现的次数,再在单调栈的循环中,每进入一次循环,我们就需要将对应的字符数量值-1,如果进入的字符比栈中的栈顶字符ascii码值小的话,那么我们需要考虑:
- 栈顶的字符的存储数量是否大于
0,如果大于0我们就可以弹出,符合条件不断进行弹出操作,如果字符串当前元素的后面没有重复的栈顶元素我们就不能进行出栈操作。 - 在出栈操作后,我们需要更新栈内有什么元素,防止漏进栈或者重复字符。
在JS中我们最后结果只需要利用
join操作就能形成字符串。
三、代码:
var removeDuplicateLetters = function(s) {
//先存储每个元素的数量
let count = new Map()
for(const c of s){
count.set(c,count.has(c)?count.get(c)+1:1)
}
let stack = []
let instack = {}
for(let i=0 ; i<s.length ; i++){
count.set(s[i],count.get(s[i])-1)
if(instack[s[i]]) continue
while(stack.length && stack[stack.length-1] >= s[i] && count.get(stack[stack.length-1]) != 0){
instack[stack.pop()] = false
}
stack.push(s[i])
instack[s[i]] = true
}
return stack.join('')
};
四、总结:
这道题目利用单调栈的思路清晰明了,我们根据题目的要求调整单调栈的策略并且修改代码,需要注意的是结果需要一个字符串,而单调栈是数组结构需要最后转化为字符串。