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(); } }