题目描述
给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的字典序最小(要求不能打乱其他字符的相对位置)。
样例描述
示例 1:
输入:s = "bcabc"
输出:"abc"
示例 2:
输入:s = "cbacdcbc"
输出:"acdb"
思路
贪心 + 单调栈思想
- 用一个字符串来记录答案,每次判断答案的最后一个字符是否大于原串当前字符,如果大于并且该字符在原串后面还出现过,就可以不断删除。然后将原串当前字符加入到答案。
- 答案字符串本质上是一个栈结果,不断在一端进行插入删除操作。
- 用一个哈希表记录是否在答案出现过,用另一个哈希表记录某字母最后出现的位置。
- 数组版和哈希表版,其实都很复杂,注意哈希表在判断是否出现过的时候,首先要判断是否存在,不然会有空指针错误。
代码
class Solution {
public String removeDuplicateLetters(String s) {
String res = "";
boolean inRes[] = new boolean[26]; //是否在答案中出现过
int lastPos[] = new int[26]; //最后出现的位置
int n = s.length();
for (int i = 0; i < n; i ++ ) {
lastPos[s.charAt(i) - 'a'] = i;
}
for (int i = 0; i < n; i ++ ) {
char c = s.charAt(i);
if (inRes[c - 'a']) continue;
while (!"".equals(res) && res.charAt(res.length() - 1) > c && lastPos[res.charAt(res.length() - 1) - 'a'] > i) {
//标记为没出现过
inRes[res.charAt(res.length() - 1) - 'a'] = false;
//去掉最后一位字符
res = res.substring(0, res.length() - 1);
}
//加入新的字符,并且标记为出现过
res += c;
inRes[c - 'a'] = true;
}
return res;
}
}
哈希表版本
class Solution {
public String removeDuplicateLetters(String s) {
String res = "";
Map<Character, Boolean> inRes = new HashMap<>(); // 是否在结果中出现
Map<Character, Integer> last = new HashMap<>(); // 最后一次出现的位置
for (int i = 0; i < s.length(); i++) last.put(s.charAt(i), i);
for (int i = 0; i < s.length(); i++) {
char cur = s.charAt(i);
//要判断是否存在key,存在的前提下才能get,不然会空指针报错
if (inRes.containsKey(cur) && inRes.get(cur)) continue; // 已经出现过,则跳过
// 若当前字符比上一个字符小,且结果中字符在后面出现过。则循环处理将比当前字符大的字符都替换掉
while (res.length() > 0 && cur < res.charAt(res.length() - 1) && last.get(res.charAt(res.length() - 1)) > i ) {
inRes.put(res.charAt(res.length() - 1), false);
res = res.substring(0, res.length() - 1);
}
res = res + cur;
inRes.put(cur, true);
}
return res;
}
}