栈:留在最后的,就是答案
用2个queue实现stack
https://leetcode-cn.com/problems/implement-stack-using-queues/
class MyStack {
Queue<Integer> queue1; // 对外输出
Queue<Integer> queue2; // 对内输入
/** Initialize your data structure here. */
public MyStack() {
queue1 = new LinkedList<Integer>();
queue2 = new LinkedList<Integer>();
}
/** Push element x onto stack. */
public void push(int x) {
queue2.offer(x);
while (!queue1.isEmpty()) {
// 核心就是让后入变成先入,最后操作的在offer处插队成为首个,过去插队维护的再输入进来即可
queue2.offer(queue1.poll());
}
Queue<Integer> temp = queue1;
queue1 = queue2;
queue2 = temp;
}
/** Removes the element on top of the stack and returns that element. */
public int pop() {
return queue1.poll();
}
/** Get the top element. */
public int top() {
return queue1.peek();
}
/** Returns whether the stack is empty. */
public boolean empty() {
return queue1.isEmpty();
}
}
439. 三元表达式解析器
https://leetcode-cn.com/problems/ternary-expression-parser/
Key point:
- Character.isDigit判断数字
- 倒推取?号。判断处理(进栈出栈)的标志为?以及之后谁进栈谁出栈,最后留下的就是答案
- 正推去:号。也可以以“:”作为判断条件,遇到:就说明要执行一次运算了。
只需要一次遍历即可
71. 简化路径
class Solution {
public String simplifyPath(String path) {
String[] strings = path.split("/");
Stack<String> stack = new Stack<>();
for(String str : strings) {
if(str.isEmpty() || str.equalsIgnoreCase(".") || str.equalsIgnoreCase("/")) {
continue;
}
if(str.equalsIgnoreCase("..")) {
if(!stack.isEmpty()) {
stack.pop();
}
continue;
}
stack.push(str);
}
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("/");
for(String str : stack) {
stringBuilder.append(str);
stringBuilder.append("/");
}
if(stringBuilder.toString().length() == 1) {
return stringBuilder.toString();
}
return stringBuilder.toString().substring(0, stringBuilder.length() - 1);
}
}
316. 去除重复字母
要点:
贪心 + stack
- stack内存放的都是经过贪心算法校验的当前最优解
每次需要判断的是即将处理的字符是否要加入,是否能够替换之前的重复字符
class Solution {
private int[] letterNum = new int[26];
public String removeDuplicateLetters(String s) {
if (s == null || s.isEmpty() || s.length() == 1) {
return s;
}
initArray(s);
Stack<Character> stack = new Stack<>();
for (int i = 0; i < s.length(); i++) {
char sTmp = s.charAt(i);
letterNum[sTmp - 'a']--;
if(stack.isEmpty()) {
stack.push(sTmp);
continue;
}
while (!stack.isEmpty()) {
// 判断当前字符与stack已经入栈字符之间的关系
char stackTmp = stack.peek();
// 已经入栈的字符无需处理
if(stack.contains(sTmp)) {
break;
}
if(stackTmp - sTmp >= 0 && !isLastOne(stackTmp)) {
// 之前入栈的每个字符需要经过新字符的洗练。需要在后续有重复的基础上满足字典序最小
stack.pop();
} else {
// 遇到第一个无法处理的立即终止
break;
}
}
if (!stack.contains(sTmp)) {
// 栈中补充上该字符
stack.push(sTmp);
}
}
StringBuilder stringBuilder = new StringBuilder();
for(Character c :stack) {
stringBuilder.append(c);
}
return stringBuilder.toString();
}
private void initArray(String s) {
for (Character c : s.toCharArray()) {
letterNum[c - 'a']++;
}
}
private boolean isLastOne(char c) {
// 判断是否是最后一个
return letterNum[c - 'a'] == 0;
}
}
循环队列
核心要点:
- 三个下标:size、first、last
想清楚first与last代表的实际意义:代表确切的存在元素的下标而不是该位置的下一个
first之间的关系是:仅有一种情况会重合。数组中只有一个元素时。
class MyCircularQueue {
Object[] queue = null;
int first = 0;
int last = 0;
int size = 0;
public MyCircularQueue(int k) {
queue = new Object[k];
first = 0;
last = 0;
size = k;
}
public boolean enQueue(int value) {
if (last + 1 == first || (last + 1 == size && first == 0)) {
// 容量占满的2种case:
// 第一遍循环的case:last到末尾
// 非第一遍的case:last之后就是first
return false;
}
if(last == first && queue[last] == null) {
// 第一个插入元素的初始化
queue[last] = value;
return true;
}
// 非第一个元素的初始化
last++;
if (last == size) {
last = 0;
}
queue[last] = value;
return true;
}
public boolean deQueue() {
if (last == first) {
if(queue[first] == null) {
return false;
} else {
queue[first] = null;
return true;
}
}
queue[first] = null;
first ++;
if (first == size) {
first = 0;
}
return true;
}
public int Front() {
if (queue[first] == null) {
return -1;
}
return (int) queue[first];
}
public int Rear() {
if (queue[last] == null) {
return -1;
}
return (int) queue[last];
}
public boolean isEmpty() {
if (last == first && queue[last] == null) {
return true;
}
return false;
}
public boolean isFull() {
int lastIndex = last + 1;
if (lastIndex == first || (lastIndex == size && first == 0)) {
return true;
}
return false;
}
}
/**
* Your MyCircularQueue object will be instantiated and called as such:
* MyCircularQueue obj = new MyCircularQueue(k);
* boolean param_1 = obj.enQueue(value);
* boolean param_2 = obj.deQueue();
* int param_3 = obj.Front();
* int param_4 = obj.Rear();
* boolean param_5 = obj.isEmpty();
* boolean param_6 = obj.isFull();
*/