1. 程式人生 > 其它 >陣列/連結串列高效去重(演算法題

陣列/連結串列高效去重(演算法題

有序陣列/連結串列去重

對於陣列相關的演算法題,有一個通用的技巧:要儘量避免在中間刪除元素,那我就先想辦法把這個元素換到最後去。這樣的話,最終待刪除的元素都拖在陣列尾部,一個一個 pop 掉就行了,每次操作的時間複雜度也就降低到 O(1) 了。

按照上面的思路可以使用雙指標的方法,我們讓慢指標slow走左後面,快指標fast走在前面探路,找到一個不重複的元素就告訴slow並讓slow前進一步。

這樣當fast指標遍歷完整個陣列nums後,nums[0..slow]就是不重複元素,之後的所有元素都是重複元素

字母去重

最後做一道算是去重演算法題中難度最大的,把這題搞懂去重部分的演算法題應該就沒問題了。

LeetCode 316 字母去重

給你一個字串 s ,請你去除字串中重複的字母,使得每個字母只出現一次。需保證 返回結果的字典序最小(要求不能打亂其他字元的相對位置)。

題目要求總結有三:

  1. 去重

  2. 不能打算輸入字串s中的字元出現的相對順序

  3. 在符合前面兩條的情況下,選出字典序最小的作為最終結果。

思路

  1. 通過使用布林陣列inStack來做到棧stk中不存在重複元素

  2. 順序遍歷字串s,通過「棧」這種順序結構的 push/pop 操作記錄結果字串,保證了字元出現的順序和s中出現的順序一致。

  3. 利用單調棧的思路以及使用計數器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();
}
}