链表实现
java
public class LinkedListStack<E> {
// 内部类:链表节点
static class Node<E> {
E value; // 节点存储的值
Node<E> next; // 指向下一个节点的引用
// 构造函数:初始化节点
public Node(E value, Node<E> next) {
this.value = value;
this.next = next;
}
}
// 栈的最大容量
private final int capacity;
// 栈中元素的数量
private int size;
// 头节点,始终指向栈顶元素的前一个节点(即哨兵节点)
private final Node<E> head = new Node<>(null, null);
/**
* 构造函数:初始化栈。
*
* @param capacity 栈的容量
*/
public LinkedListStack(int capacity) {
this.capacity = capacity;
}
/**
* 向栈中添加一个元素。
*
* @param value 要添加的元素
* @return 如果成功添加返回 true;如果栈已满返回 false
*/
public boolean push(E value) {
if (isFull()) {
return false;
}
// 将新元素插入到头节点之后
head.next = new Node<>(value, head.next);
size++;
return true;
}
/**
* 从栈中移除并返回栈顶元素。
*
* @return 栈顶元素;如果栈为空返回 null
*/
public E pop() {
if (isEmpty()) {
return null;
}
// 获取栈顶元素
Node<E> first = head.next;
// 更新头节点的 next 指针,跳过栈顶元素
head.next = first.next;
size--;
return first.value;
}
/**
* 返回栈顶元素但不移除它。
*
* @return 栈顶元素;如果栈为空返回 null
*/
public E peek() {
if (isEmpty()) {
return null;
}
return head.next.value;
}
/**
* 判断栈是否为空。
*
* @return 如果栈为空返回 true,否则返回 false
*/
public boolean isEmpty() {
return head.next == null;
}
/**
* 判断栈是否已满。
*
* @return 如果栈已满返回 true,否则返回 false
*/
public boolean isFull() {
return size == capacity;
}
}
数组实现
java
public class ArrayStack<E> {
// 使用泛型数组存储栈中的元素
private final E[] array;
// 栈顶指针,初始化为0,指向下一个要插入元素的位置
private int top = 0;
// 构造函数,初始化栈的容量
@SuppressWarnings("unchecked") // 抑制编译器关于类型转换的警告
public ArrayStack(int capacity) {
// 创建指定容量的Object数组并强制转换为E类型数组
this.array = (E[]) new Object[capacity];
}
/**
* 将元素压入栈中。
* 如果栈已满,则返回false表示失败;否则将元素加入栈并返回true。
*/
public boolean push(E value) {
if (isFull()) { // 检查栈是否已满
return false;
}
array[top] = value; // 放置元素到当前栈顶位置
top++; // 增加栈顶指针
return true;
}
/**
* 弹出栈顶元素。
* 如果栈为空,则返回null;否则移除并返回栈顶元素。
*/
public E pop() {
if (isEmpty()) { // 检查栈是否为空
return null;
}
top--; // 减少栈顶指针,指向新的栈顶
return array[top]; // 返回被移除的栈顶元素
}
/**
* 查看栈顶元素但不移除它。
* 如果栈为空,则返回null;否则返回栈顶元素。
*/
public E peek() {
if (isEmpty()) { // 检查栈是否为空
return null;
}
return array[top - 1]; // 返回栈顶元素
}
/**
* 判断栈是否为空。
* 如果栈顶指针为0,则栈为空。
*/
public boolean isEmpty() {
return top == 0;
}
/**
* 判断栈是否已满。
* 如果栈顶指针等于数组长度,则栈已满。
*/
public boolean isFull() {
return top == array.length;
}
}
有效的括号-Leetcode 20
给定一个只包括
'('
,')'
,'{'
,'}'
,'['
,']'
的字符串s
,判断字符串是否有效。有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
- 每个右括号都有一个对应的相同类型的左括号。
示例 1:
**输入:**s = "()"
**输出:**true
示例 2:
**输入:**s = "()[]{}"
**输出:**true
示例 3:
**输入:**s = "(]"
**输出:**false
示例 4:
**输入:**s = "([])"
**输出:**true
java
public boolean isValid(String s) {
ArrayStack<Character> stack = new ArrayStack<>(s.length()/2+1);
for (int i = 0; i < s.length(); i++) {
char c=s.charAt(i);
if(c=='(') {
stack.push(')');
}else if (c == '[') {
stack.push(']');
} else if (c == '{') {
stack.push('}');
}else {
if(!stack.isEmpty() && stack.peek()==c) {
stack.pop();
}else {
return false;
}
}
}
return stack.isEmpty();
}
public class ArrayStack<E>{
private final E[] array;
private int top = 0;
@SuppressWarnings("all")
public ArrayStack(int capacity) {
this.array = (E[]) new Object[capacity];
}
public boolean push(E value) {
if (isFull()) {
return false;
}
array[top++]=value;
return true;
}
public E pop() {
if (isEmpty()) {
return null;
}
return array[--top];
}
public E peek() {
if (isEmpty()) {
return null;
}
return array[top-1];
}
public boolean isEmpty() {
return top == 0;
}
public boolean isFull() {
return top == array.length;
}
}
}
逆波兰表达式求值-Leetcode 150
给你一个字符串数组
tokens
,表示一个根据 逆波兰表示法 表示的算术表达式。请你计算该表达式。返回一个表示表达式值的整数。
注意:
- 有效的算符为
'+'
、'-'
、'*'
和'/'
。- 每个操作数(运算对象)都可以是一个整数或者另一个表达式。
- 两个整数之间的除法总是 向零截断 。
- 表达式中不含除零运算。
- 输入是一个根据逆波兰表示法表示的算术表达式。
- 答案及所有中间计算结果可以用 32 位 整数表示。
示例 1:
输入:tokens = ["2","1","+","3","*"] 输出:9 解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9
示例 2:
输入:tokens = ["4","13","5","/","+"] 输出:6 解释:该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6
示例 3:
输入:tokens = ["10","6","9","3","+","-11","*","/","*","17","+","5","+"] 输出:22 解释:该算式转化为常见的中缀算术表达式为: ((10 * (6 / ((9 + 3) * -11))) + 17) + 5 = ((10 * (6 / (12 * -11))) + 17) + 5 = ((10 * (6 / -132)) + 17) + 5 = ((10 * 0) + 17) + 5 = (0 + 17) + 5 = 17 + 5 = 22
java
public int evalRPN(String[] tokens) {
Deque<Integer> numbers = new LinkedList<Integer>();
for(String t:tokens) {
switch(t) {
case "+" ->{
Integer b = numbers.pop();
Integer a = numbers.pop();
numbers.push(a + b);
}case "-" -> {
Integer b = numbers.pop();
Integer a = numbers.pop();
numbers.push(a - b);
}
case "*" -> {
Integer b = numbers.pop();
Integer a = numbers.pop();
numbers.push(a * b);
}
case "/" -> {
Integer b = numbers.pop();
Integer a = numbers.pop();
numbers.push(a / b);
}
default -> numbers.push(Integer.parseInt(t));
}
}
return numbers.pop();
}
拓:中缀表达式转后缀
java
static String infixToSuffix(String exp) {
LinkedList<Character> stack = new LinkedList<>();
StringBuilder sb = new StringBuilder(exp.length());
for (int i = 0; i < exp.length(); i++) {
char c = exp.charAt(i);
switch (c) {
case '+', '-', '*', '/' -> {
if (stack.isEmpty()) {
stack.push(c);
} else {
if (priority(c) > priority(stack.peek())) {
stack.push(c);
} else {
while (!stack.isEmpty()
&& priority(stack.peek()) >= priority(c)) {
sb.append(stack.pop());
}
stack.push(c);
}
}
}
case '(' -> {
stack.push(c);
}
case ')' -> {
while (!stack.isEmpty() && stack.peek() != '(') {
sb.append(stack.pop());
}
stack.pop();
}
default -> {
sb.append(c);
}
}
}
while (!stack.isEmpty()) {
sb.append(stack.pop());
}
return sb.toString();
}
static int priority(char c) {
return switch (c) {
case '(' -> 0;
case '*', '/' -> 2;
case '+', '-' -> 1;
default -> throw new IllegalArgumentException("不合法字符:" + c);
};
}
双栈模拟队列-Leetcode 232
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(
push
、pop
、peek
、empty
):实现
MyQueue
类:
void push(int x)
将元素 x 推到队列的末尾int pop()
从队列的开头移除并返回元素int peek()
返回队列开头的元素boolean empty()
如果队列为空,返回true
;否则,返回false
说明:
- 你 只能 使用标准的栈操作 ------ 也就是只有
push to top
,peek/pop from top
,size
, 和is empty
操作是合法的。- 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
示例 1:
输入: ["MyQueue", "push", "push", "peek", "pop", "empty"] [[], [1], [2], [], [], []] 输出: [null, null, null, 1, 1, false]
java
class MyQueue {
Deque<Integer> s1;
Deque<Integer> s2;
public MyQueue() {
s1 = new ArrayDeque<Integer>(100);
s2 = new ArrayDeque<Integer>(100);
}
public void push(int x) {
s2.push(x);
}
public int pop() {
if(s1.isEmpty()) {
while(!s2.isEmpty()) {
s1.push(s2.pop());
}
}
return s1.pop();
}
public int peek() {
if(s1.isEmpty()) {
while(!s2.isEmpty()) {
s1.push(s2.pop());
}
}
return s1.peek();
}
public boolean empty() {
return s1.isEmpty() && s2.isEmpty();
}
}
单队列模拟栈-Leetcode 225
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(
push
、top
、pop
和empty
)。实现
MyStack
类:
void push(int x)
将元素 x 压入栈顶。int pop()
移除并返回栈顶元素。int top()
返回栈顶元素。boolean empty()
如果栈是空的,返回true
;否则,返回false
。注意:
- 你只能使用队列的标准操作 ------ 也就是
push to back
、peek/pop from front
、size
和is empty
这些操作。- 你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
示例:
输入: ["MyStack", "push", "push", "top", "pop", "empty"] [[], [1], [2], [], [], []] 输出: [null, null, null, 2, 2, false] 解释: MyStack myStack = new MyStack(); myStack.push(1); myStack.push(2); myStack.top(); // 返回 2 myStack.pop(); // 返回 2 myStack.empty(); // 返回 False
java
public class MyStack {
Queue<Integer> queue;
int size=0;
MyStack() {
queue= new LinkedList<Integer>();
}
public void push(int x) {
queue.offer(x);
for(int i=0;i<size;i++) {
queue.offer(queue.poll());
}
size++;
}
public int pop() {
size--;
return queue.poll();
}
public int top() {
return queue.peek();
}
public boolean empty() {
return queue.isEmpty();
}
}