题目:
给定一个仅包含小写字母的字符串,去除字符串中重复的字母,使得每个字母只出现一次。需保证返回结果的字典序最小(要求不能打乱其他字符的相对位置)。
示例 1:
输入: "bcabc"
输出: "abc"
示例 2:
输入: "cbacdcbc"
输出: "acdb"
分析:
1.什么叫字典序:26个英文字母的顺序
2.什么叫字符的相对位置,就是你只能删除重复的但是不能左右移动元素
我们来模拟下从第一个元素到最后一个元素的过程算法就出来了:
step1:c
step2:cb
step3:cba
step4:bac
step5:bacd
step6:acdb
按照我们的思维来写算法:定义一个结果集,依次遍历每个元素,结果集不存在就加入,如果存在就判断两个元素之间的元素有没有比当前元素小的,有的话就删掉之前的,比如bacdb,两个b之间有a比b小,所以要删掉之前的b,改成acdb
这里用另一个方法栈+标志来实现
说明:栈中存的元素满足两个条件之一就可以:1.元素都是递增的,2,当前元素在后续不在出现(过了这个村就没这个店了)
算法:
package com.bysj.common.算法;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
/**
* 给定一个仅包含小写字母的字符串,去除字符串中重复的字母,使得每个字母只出现一次。需保证返回结果的字典序最小(要求不能打乱其他字符的相对位置)。
* <p>
* 示例 1:
* <p>
* 输入: "bcabc"
* 输出: "abc"
* <p>
* 示例 2:
* <p>
* 输入: "cbacdcbc"
* 输出: "acdb"
*/
public class 去除重复字母 {
public static String removeDuplicateLetters(String s) {
if (s == null || s.equals("")) {
return "";
}
char[] strArr = s.toCharArray();
return getResult(strArr);
}
public static String getResult(char[] strArr) {
String result = "";
//记录所有几点的最后一个出现的位置
Map<Character, Integer> memory = new HashMap<>();
//记录哪些节点已经放入了栈中
Map<Character, Boolean> memory2 = new HashMap<>();
Stack<Character> stack = new Stack();
for (int i = 0; i < strArr.length; i++) {
memory.put(strArr[i], i);
memory2.put(strArr[i], false);
}
//第一个元素特殊处理下便于理解
stack.add(strArr[0]);
memory2.put(strArr[0], true);
for (int i = 1; i < strArr.length; i++) {
//如果节点没有出现在栈中
if (!memory2.get(strArr[i])) {
//如果栈顶节点大于当前节点并且该节点后续还会出现,取出栈顶节点然后继续取栈第二节点继续比较
while (!stack.isEmpty() && strArr[i] < stack.peek()) {
if (memory.get(stack.peek()) > i) {
memory2.put(stack.peek(), false);
stack.pop();
} else {
break;
}
}
//当循环完了后,当前节点肯定大于栈顶元素,入栈,记录该节点已经入栈了
stack.push(strArr[i]);
memory2.put(strArr[i], true);
}
}
StringBuilder stringBuilder = new StringBuilder();
while (!stack.empty()) {
stringBuilder.insert(0, stack.pop());
}
return stringBuilder.toString();
}
public static void main(String[] args) {
String result = removeDuplicateLetters("bacacca");
System.out.println(result);
}
}