理论基础
Java Stack类
The Stack class extends class Vector, representing s LIFO(last-in-first-out) stack of objects.
Constructor
Stack<E> st = new Stack<E>(); // creates an empty stack
Methods
public boolean empty()当且仅当栈中没有元素时返回truepublic E peek()返回栈顶元素public E pop()移除栈顶元素并返回public E push(E item)把item元素添加到栈顶public int search(Object o)返回o在栈中的位置(有多个则为最小的位置),栈顶元素为1,不存在则返回-1
Java Queue接口
Queues order elements in a FIFO(first-in-first-out) manner. Queue接口常用的两个实现:PriorityQueue类,LinkedList类
Methods
boolean add(E e)如果有空间就插入元素e,返回true,没有空闲空间则抛出IllegalStateException异常boolean offer(E e)如果有空间就插入元素e,返回true;否则返回false,注意与add方法的区别E element()获取队列头,但不移除;如果队列为空,抛出NoSuchElementExceptionE peek()获取队列头,但不移除;如果队列为空,返回nullE remove()获取并移除队列头,若队列为空则抛出IllegalStateException异常E poll()获取并移除队列头,若队列为空返回null
LeetCode 232 用栈实现队列
思路
栈是单侧出入,队列是两侧出入。故我们使用两个栈模拟队列。 栈的行为是先进后出,队列的行为是先进先出。 考虑两个栈stackA和stackB如何模拟队列行为:
- 两个栈初始为空
- 元素e入队
- 元素e入栈stackA
- 元素e出队(此时应该让stackA中栈底的元素出栈)
- 如果stackB为空
- 依次对stackA中所有元素先出栈,后入栈stackB(那么B中元素的出栈顺序就和这些元素入栈A时相同,完成了先进先出的模拟)
- stackB.pop
- 如果B不空则直接pop
- 如果stackB为空
解法
class MyQueue {
private Stack<Integer> stackA;
private Stack<Integer> stackB;
public MyQueue() {
stackA = new Stack<>();
stackB = new Stack<>();
}
public void push(int x) {
stackA.push(x);
}
public int pop() {
if (stackB.empty()) {
while (!stackA.empty()) {
int e = stackA.pop();
stackB.push(e);
}
}
return stackB.pop();
}
public int peek() {
if (stackB.empty()) {
while (!stackA.empty()) {
int e = stackA.pop();
stackB.push(e);
}
}
return stackB.peek();
}
public boolean empty() {
return stackA.empty() && stackB.empty();
}
}
LeetCode 225 用队列实现栈
思路
考虑用队列的标准操作模拟栈的操作:
- 元素入栈:
- 元素入队
- 元素出栈:(需要把队尾的元素出队)
- 队列中有n个元素,把前n-1个元素出队保存起来,第n个元素出队返回
- 具体如何保存:可以放入另一个队列or直接再次入队
- 获取栈顶元素:
- 队列中有n个元素,把前n-1个元素出队后入队,第n个元素读取后也入队
解法
class MyStack {
private Queue<Integer> queue;
public MyStack() {
queue = new LinkedList<>();
}
public void push(int x) {
queue.offer(x);
}
public int pop() {
int n = queue.size();
for (int i = 0; i < n-1; i++) {
int e = queue.poll();
queue.offer(e);
}
return queue.poll();
}
public int top() {
int n = queue.size();
for (int i = 0; i < n-1; i++) {
int e = queue.poll();
queue.offer(e);
}
int result = queue.poll();
queue.offer(result);
return result;
}
public boolean empty() {
return queue.isEmpty();
}
}
LeetCode 20 有效的括号
思路
很经典的用栈解决的题目
- 当栈空,括号入栈
- 当栈顶括号和现在的括号可以左右匹配,栈顶括号出栈
- 不可以匹配则括号入栈
- 当字符串被遍历完,如果栈空,则有效;否则无效
解法
class Solution {
public boolean isValid(String s) {
Stack<Character> stack = new Stack<>();
for (int i = 0; i < s.length(); i++) {
if (stack.empty()) {
stack.push(s.charAt(i));
}
else if (match(stack.peek(), s.charAt(i))) {
stack.pop();
}
else {
stack.push(s.charAt(i));
}
}
if (stack.empty()) {
return true;
}
return false;
}
private boolean match(char i, char j) {
if (i == '(' && j==')') {
return true;
}
if (i == '[' && j==']') {
return true;
}
if (i == '{' && j=='}') {
return true;
}
return false;
}
}
LeetCode 1047 删除字符串中所有的相邻重复项
思路
相邻重复项的性质和上题括号相似,对字符串中每个字符遍历
- 当栈空,字符入栈
- 当栈顶字符与当前字符相同,栈顶字符出栈
- 否则,字符入栈
- 遍历完成后,返回栈中剩余的字符组成的字符串
解法
class Solution {
public String removeDuplicates(String s) {
Stack<Character> stack = new Stack<>();
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if (stack.empty()) {
stack.push(ch);
}
else if (stack.peek() == ch) {
stack.pop();
}
else {
stack.push(ch);
}
}
char[] charArr = new char[stack.size()];
for (int i = charArr.length-1; i >= 0; i--) {
charArr[i] = stack.pop();
}
return new String(charArr);
}
}
今日收获总结
今日学习2.5小时,第二次刷,栈的掌握还算比较好,题目更典型