前一篇文章中接触了单调栈的问题,今天的题目中也采用了单调栈相关技巧 去除字符串中的重复字符
一、去除重复字母316
1、分析
题目有三个要求
(1)首先要保证每个字母出现的相对顺序和原数组中相同——单调栈保证顺序
(2)然后就要求每个字母在结果中只出现一次——严格控制出现次数
(3)还要保证返回结果的字典序最小——即要保证字典序小的字符要在前面;可以考虑将栈中大于当前元素的内容出栈,然后将当前元素入栈。但是在出栈操作前,还要考虑到每个元素都要出现一次这点,所以就看栈顶元素在后续是否还有出现机会(这里我们可以采用字典去保存字符串中的所有元素总共的数量,每当遍历到一次就将该字符对应的总数减一)
具体见代码和注释
2、代码
class Solution:
def smallestSubsequence(self, s: str) -> str:
count = Counter(s) #用于记录每个元素的个数
stack = []
for c in s:
count[c] -= 1
if c in stack: #保证每个元素不重复出现
continue
while stack and stack[-1]>=c: #利用单调栈,保证原来数组中的次序,并保证最终结果的字典序
if count[stack[-1]]==0: #防止丢失元素,若栈顶元素在后面不再出现,那么不能出栈
break
stack.pop()
stack.append(c)
return ''.join(stack) #将数组转变为字符串形式
JS
/**
* @param {string} s
* @return {string}
*/
var smallestSubsequence = function(s) {
let stack = [],count = {};
for(let c of s){
if(c in count){
count[c] += 1;
}else{
count[c] = 1;
}
}
for(let c of s){
count[c] -= 1;
if(stack.includes(c)){
continue;
}
while(stack.length!=0 && stack[stack.length-1]>=c){
if(count[stack[stack.length-1]]==0){
break;
}
stack.pop();
}
stack.push(c);
}
return stack.join('')
};
二、不同字符的最小子序列 1081
与上一题完全一样。