Given a string which contains only lowercase letters, remove duplicate letters so that every letter appear once and only once. You must make sure your result is the smallest in lexicographical order among all possible results.數組
Example:
Given "bcabc"
Return "abc"appGiven "cbacdcbc"
Return "acdb"優化
這道題能夠採用Greedy的思想,由於最後想要的結果是最小值,因此咱們在知足要求的狀況下把不斷append最小的字符, 最後即可獲得最小的字符串.ui
關鍵點就是要知足什麼要求以及怎麼樣去知足。首先要求就是得保證在原來的字符串中存在當前字符append的順序,即要保證每次append的字符的次數大於0。咱們能夠用一個數組記錄每一個字符出現的次數,用一個指針從左到右掃,過程當中減少對應字符次數,找當前最小字符, 找的過程當中終止條件是發現某個字符次數等於0,由於繼續掃的話最終結果頗有可能缺那個字符.spa
其實跟上個方法差很少,可是能夠優化下,用stack的話,最多每一個字符過兩遍就能夠了。讀字符的過程當中,把字符存到stack裏,當發現stack以前存的字符中比當前字符大並且頻率還大於0就能夠把那個字符pop出去。相似這種題目均可以用stack解決。基本思想就是在必定的限制條件下pop出比當前選擇差的元素。指針
time: O(kn), space: O(k), k表示原字符串中unique字符的個數code
time: O(n), space: O(k)rem
public class Solution { public String removeDuplicateLetters(String s) { if (s == null ||s.length() == 0) return s; // 記錄每一個字符出現的次數 int[] cnt = new int[26]; for (int i = 0; i < s.length(); i++) { cnt[s.charAt(i) - 'a']++; } // 找出當前最小字符 int pos = 0; for (int i = 0; i < s.length(); i++) { if (s.charAt(i) < s.charAt(pos)) pos = i; // 避免無字符可用 if (--cnt[s.charAt(i) - 'a'] == 0) break; } // 除去字符串中已經append的字符的全部重複值 return s.charAt(pos) + removeDuplicateLetters(s.substring(pos + 1).replaceAll("" + s.charAt(pos), "")); } }
public class Solution { public String removeDuplicateLetters(String s) { int[] freqs = new int[256]; // 統計字符頻率 for (int i = 0; i < s.length(); i++) { freqs[s.charAt(i)]++; } boolean[] visited = new boolean[256]; // 用來標記存在stack裏的字符 Deque<Character> q = new ArrayDeque<>(); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); freqs[c]--; if (visited[c]) continue; // pop出stack當中比當前字符大但後面還存在的的字符, while (!q.isEmpty() && q.peek() > c && freqs[q.peek()] > 0) { visited[q.pop()] = false; } q.push(c); visited[c] = true; } StringBuilder sb = new StringBuilder(); for (char c : q) { sb.append(c); } return sb.reverse().toString(); } }