題目:去除重復字母
給你一個字符串 s ,請你去除字符串中重復的字母,使得每個字母只出現一次。需保證 返回結果的字典序最小(要求不能打亂其他字符的相對位置)。
示例 1:
輸入:s = “bcabc”
輸出:“abc”
示例 2:
輸入:s = “cbacdcbc”
輸出:“acdb”
其實這道題我覺得和 402. 移掉 K 位數字很像的,這道題的題解可以看一下單調棧的總結與案例復盤。
思路:
402 是構造單調遞增棧的過程中,通過k的數量判斷要不要將棧頂元素彈出。
316 是構造單調遞增棧的過程中,通過 尚未遍歷的元素中(restMap
)是否還有和棧頂元素重復的元素,如果沒有了,那么棧頂元素不可以去除,否則可以去除。
316 還需要判斷一下棧內(usedMap
)是否有這個元素,如果已經有了,也不可以入棧。
316 中需要用兩個map來維護棧內的元素個數 和 尚未遍歷的元素個數。
var removeDuplicateLetters = function(s) {let restMap = new Map();let usedMap = new Map();for(let i = 0; i < s.length; i++){if(!restMap.has(s[i])){restMap.set(s[i],0);} restMap.set(s[i],restMap.get(s[i])+1); usedMap.set(s[i], 0);}let stack = [];for(let i = 0; i < s.length; i++){restMap.set(s[i],restMap.get(s[i])-1);// 如果棧里已經有了就不要再入棧了,比如棧里有ab,如果當前元素是a,// 那么a就會將b彈出,不會彈出a,又因為棧里已經有a,所以當前元素也不會將元素壓入棧中,// 因此無緣無故彈出一個元素,我們一定要清楚,彈出元素是為了不破壞單調性,不彈也不會破環。if(usedMap.get(s[i]) === 1){continue;}//構造單調遞增while(stack.length && s[i] < stack[stack.length-1] && restMap.get(stack[stack.length-1]) > 0){let top = stack.pop();usedMap.set(top,0);} // 棧里沒有才能往里面放stack.push(s[i]);usedMap.set(s[i],1);}return stack.join('');};