这篇文章让我们来聊聊关于数组去重问题的算法
话不多说,直接上题
316. 去除重复字母
分析
- 这个题目一共有三个要求
- 要求一:数组去重
- 要求二:不能打乱字符的相对位置
- 要求三:返回结果的字典序最小(abc的字典序比acb的小)
对于要求一和要求二,我们直接用栈就可以实现
//js代码,使用数组的模拟栈操作
var removeDuplicateLetters = function(s) {
let stack = [], res = [];
for(let i = 0; i < s.length; i++) {
if(stack.includes(s[i])){
continue;
}
stack.unshift(s[i]);
}
res = stack.reverse();
return res.join('');
};
那么要求三我们该怎么来实现呢?
- 比如:s =“bcabc”,按照上面的解法我们能得到bca,但是结果应该是abc,看看它们之间的区别,那就是开头的bc被我们舍去了。我们什么时候舍去呢?因为要求三是找字典序最小,所以如果这个时候的字符是a,因为b和c比a大,所以我们直接舍去。
- 如果输入变成了s=“bcac”,按照之前的舍去,我们会得到一个错误的答案ac,正确答案应该是bac,b被我们舍去了,所以在舍去的条件上我们还需要加上:如果后面再也没有这个字符了,我们就不能舍去它。
- 对于我们如何判断在这个元素之后是否还有前面的那些元素,我们只需要将所有的字符记录个数,每次循环时,将当前字符的个数减一。
- 上面我们使用的栈,所以我们只需要让当前字符和栈顶元素进行比较就行了。
代码
/**
*js代码
* @param {string} s
* @return {string}
*/
var removeDuplicateLetters = function(s) {
let stack = [], res = [];
let count = new Map();
//记录所有字符的个数
for(let j = 0; j < s.length; j++) {
if(!count.has(s[j])) {
count.set(s[j],1);
} else {
count.set(s[j],count.get(s[j])+1);
}
}
for(let i = 0; i < s.length; i++) {
//每次循环,将当前字符个数减一
count.set(s[i],count.get(s[i])-1);
if(stack.includes(s[i])){
continue;
}
//判断是否去除当前字符前面的字符
while(s[i] < stack[0] && stack.length!==0 && count.get(stack[0])>=1) {
stack.shift();
}
stack.unshift(s[i]);
}
res = stack.reverse();
return res.join('');
};
以上题解参考自labuladong的算法秘籍