题目描述(传送门)
给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的字典序最小(要求不能打乱其他字符的相对位置)。
示例
示例 1:
输入:s = "bcabc"
输出:"abc"
示例 2:
输入:s = "cbacdcbc"
输出:"acdb"
思路
这里首先来看看代码
import java.util.ArrayDeque;
import java.util.Deque;
/**
* @ClassName Demo
* @Description ${DESCRIPTION}
* @Author Fangwenhui
* @Date 2020/12/20/15:46
*/
public class Demo {
public static String removeDuplicateLetters(String s) {
int len = s.length();
char[] charArray = s.toCharArray();// 转为字符数组
int[] lastIndex = new int[26];
for (int i = 0; i < len ; i++) {
lastIndex[charArray[i] - 'a'] = i;//保存字符串中字符最后出现的下标,后边用于判断该元素后边还会不会出现
}
Deque<Character> stack = new ArrayDeque<>();// 双端队列尾插尾删当作栈使用
boolean[] visited = new boolean[26];// 监视栈里边的元素
for (int i = 0; i < len ; i++) {
if (visited[charArray[i] - 'a']) {
continue;// 如果栈内已经出现,那么这里为什莫可以直接舍弃呢,如果栈里边已经存在,如果不丢弃则不能保证最小字典序
// 如果当前看到的字母已经在栈中,则它一定不是某一段单点递增字母的最后一个字母,所以可以直接舍弃
}
while (!stack.isEmpty() && stack.peekLast() > charArray[i] && lastIndex[stack.peekLast() - 'a'] > i) {
// 栈顶元素大于字符数组的元素,并且后边还会出现的话就移出栈顶元素
Character top = stack.removeLast();
visited[top - 'a'] = false;// 维护visited
}// 注意这里是while循环,循环结束后保证栈里边都是按照字典序排好的
stack.addLast(charArray[i]);//说明可以入栈
visited[charArray[i] - 'a'] = true;// 维护visited
}
// 程序走到这里,栈里边保存的就是结果
StringBuilder stringBuilder = new StringBuilder();
for (char c : stack) {
//System.out.println(c);//注意的是这里用的是双端队列,从头在加入StringBuffer 这样就避免使用栈后还需要反转的问题
stringBuilder.append(c);
//System.out.println(stringBuilder.toString());
}
return stringBuilder.toString();
}
public static void main(String[] args) {
System.out.println(removeDuplicateLetters("aqaqwe").toString());
}
}
首先将字符串转为字符数组,这样就和小标关联起来。方便操作。
需要二个数组,
== lastIndex ==负责记录每个元素在字符串中最后出现的下标;
visited负责记录栈中的元素是否存在,使用Boolean数组
以及需要一个双端队列,和StringBuffer。具体解释见代码里边。