陣列/連結串列高效去重(演算法題
阿新 • • 發佈:2022-01-08
對於陣列相關的演算法題,有一個通用的技巧:要儘量避免在中間刪除元素,那我就先想辦法把這個元素換到最後去。這樣的話,最終待刪除的元素都拖在陣列尾部,一個一個 pop 掉就行了,每次操作的時間複雜度也就降低到 O(1) 了。
這樣當fast
指標遍歷完整個陣列nums
後,nums[0..slow]
就是不重複元素,之後的所有元素都是重複元素
字母去重
最後做一道算是去重演算法題中難度最大的,把這題搞懂去重部分的演算法題應該就沒問題了。
LeetCode 316 字母去重
給你一個字串
s
,請你去除字串中重複的字母,使得每個字母只出現一次。需保證 返回結果的字典序最小(要求不能打亂其他字元的相對位置)。
題目要求總結有三:
-
去重
-
不能打算輸入字串s中的字元出現的相對順序
-
在符合前面兩條的情況下,選出字典序最小的作為最終結果。
思路
-
通過使用布林陣列inStack來做到棧stk中不存在重複元素
-
順序遍歷字串
s
,通過「棧」這種順序結構的 push/pop 操作記錄結果字串,保證了字元出現的順序和s
中出現的順序一致。 -
利用單調棧的思路以及使用計數器count來不斷pop掉不符合最小字典序的字元。
class Solution {
public String removeDuplicateLetters(String s) {
//存放去重結果
Stack<Character> stk = new Stack<>();
int[] count = new int[256];
for(int i=0;i<s.length();i++){
count[s.charAt(i)]++;
}
boolean[] inStack = new boolean[256];
for(char c:s.toCharArray()){
count[c]--;
if(inStack[c]) continue;
while(!stk.isEmpty()&&stk.peek()>c){
if(count[stk.peek()]==0){
break;
}
inStack[stk.pop()] = false;
}
stk.push(c);
inStack[c] = true;
}
StringBuilder sb = new StringBuilder();
while(!stk.isEmpty()){
sb.append(stk.pop());
}
//由於棧是先進後出的,所以要反轉一次才是最終結果
return sb.reverse().toString();
}
}