316. Remove Duplicate Letters

时间:2022-06-14 21:56:38

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"

Given "cbacdcbc"
Return "acdb"

解题思路:

abccdab

第一步:字母去重abcdab

第二步:map中存放{d=3, b=5, c=2, a=4}

第三步:拼接输出

原理:第一个元素一定会出现在0到2之间(因为字符串中最后一次出现c的位置为2,如果0到2之间没有出现一个元素,那么拼接的字符串将不会有c这个字符)

   0到2之间一定会出现角标为2处的元素大于1次,并且角标为2处的元素为当前拼接的字符串中最大的。

根据这个原理来控制b与end的值并且选择(b,end]中最小的元素,拼接字符串。

 public class Solution {
public String removeDuplicateLetters(String s) {
// 字母去重
Character old=null;
Character newc;
StringBuilder stb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
newc = s.charAt(i);
if (old!=newc) {
stb.append(newc);
}
old = newc;
}
s = stb.toString(); // 利用map的自动覆盖得到最后出现的字母角标键值对
Map<Character,Integer> map = new HashMap<Character,Integer>();
for (int i = 0; i < s.length(); i++) {
map.put(s.charAt(i), i);
}
int len = map.size(); // 利用StringBuilder来拼接输出
StringBuilder sb = new StringBuilder();
int b=0;
int end = findMinValue(map);
Character val = findKeyByValue(map,end);
while (sb.length()<len) {
Character minc='z'+1;
for (int i = b; i <= end; i++) {
Character cm = s.charAt(i);
if (cm<minc&&cm<=val&&map.containsKey(cm)) {
minc = cm;
b=i+1;
}
}
sb.append(minc+"");
// 从map中删除
map.remove(minc);
if(minc == val){
end = findMinValue(map);
val = findKeyByValue(map,end);
}
} return sb.toString();
}
public Character findKeyByValue(Map<Character,Integer> map,int val){
for (Map.Entry<Character,Integer> entry: map.entrySet()) {
if (entry.getValue()==val) {
return entry.getKey();
}
}
return null;
}
public int findMinValue(Map<Character,Integer> map){
int minkey = Integer.MAX_VALUE;
for (Integer index : map.values()) {
if (index<minkey) {
minkey = index;
}
}
return minkey;
}
}

此题的关键在于第30行代码处:对每一个将要输出的字母范围进行限制。