栈
特殊的线性表,只允许在一端进行插入和删除元素的操作,遵循先入后出的原则。
自己生成一个栈以及其方法
//添加元素
public void push(int val){
if (isFull()){
elem= Arrays.copyOf(elem,2*elem.length);
}
elem[useSize]=val;
useSize++;
}
//判满操作
public boolean isFull(){
if (useSize==elem.length){
return true;
}
return false;
}
//删除元素
public int pop(){
if (isEmpty()){
throw new EmptyStackExpextion("数组越界异常");
}
int oldVal=elem[useSize-1];
useSize--;
return oldVal;
}
//判空操作
public boolean isEmpty(){
return useSize==0;
}
//获取栈顶元素
public int peek(){
if (isEmpty()){
throw new EmptyStackExpextion("栈为空了");
}
return elem[useSize-1];
}
//栈大小
public int size(){
return useSize;
}
如果用单向链表表示栈,建议使用头插法:
入栈:O(1),从头结点插入不需要遍历列表
出栈:O(1),删除头结点
如果用双向链表表示:
从头入栈,从头出栈;从尾入栈,从尾出栈
例题:根据 逆波兰表示法,求表达式的值。
有效的算符包括 +
、-
、*
、/
。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
https://leetcode.cn/problems/evaluate-reverse-polish-notation/description/
class Solution {
public int evalRPN(String[] tokens) {
Deque<Integer> stack = new LinkedList<Integer>();
int n = tokens.length;
for (int i = 0; i < n; i++) {
String token = tokens[i];
if (isNumber(token)) {
stack.push(Integer.parseInt(token));
} else {
int num2 = stack.pop();
int num1 = stack.pop();
switch (token) {
case "+":
stack.push(num1 + num2);
break;
case "-":
stack.push(num1 - num2);
break;
case "*":
stack.push(num1 * num2);
break;
case "/":
stack.push(num1 / num2);
break;
default:
}
}
}
return stack.pop();
}
public boolean isNumber(String token) {
return !("+".equals(token) || "-".equals(token) || "*".equals(token) || "/".equals(token));
}
}
时间复杂度:O(n),其中 n是数组 tokens的长度。需要遍历数组 tokens 一次,计算逆波兰表达式的值。
空间复杂度:O(n),其中 n是数组 tokens的长度。使用栈存储计算过程中的数,栈内元素个数不会超过逆波兰表达式的长度。
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。
1. 0<=pushV.length == popV.length <=1000
2. -1000<=pushV[i]<=1000
3. pushV 的所有数字均不相同
https://www.nowcoder.com/practice/d77d11405cc7470d82554cb392585106?tpId=13&tqId=11174&ru=/exam/oj
if (pushA. length != popA.length){
return false;
}
Stack<Integer> stack=new Stack<>();
int j=0;
for(int i=O;i<pushA. length;i++){
stack.push(pushA[i]);
while(j<popA.length && !stack.empty() && stack.peek()=-popA[j]){}
stack.pop();
j++;
}
return stack. empty();
队列
是一个特殊线性表,只允许从一端插入数据,在另一端进行删除数据,遵循先进先出的原则。
队列的方法
//入队
public void offer(int val){
Node node=new Node(val);
if (head==null){
head=node;
tail=node;
}else {
tail.next=node;
tail=node;
}
}
//出队
public int poll(){
if (head==null){
return -1;
}
int oldVal=head.val;
if (head.next==null){
head=null;
tail=null;
}else {
head=head.next;
}
return oldVal;
}
//查看队首元素
public int peek(){
if (head==null){
return -1;
}
return head.val;
}
循环队列
class MyCircularQueue {
public int[] elem;
public int front;//队头下标
public int rear;//队尾下标
public MyCircularQueue(int k) {
this.elem=new int[k+1];
}
public boolean enQueue(int value) {
if(isFull()){
return false;
}
this.elem[rear]=value;
rear=(rear+1)%elem.length;
return true;
}
public boolean deQueue() {
if(isEmpty()){
return false;
}
front=(front+1)%elem.length;
return true;
}
public int Front() {
if(isEmpty()){
return -1;
}
return elem[front];
}
public int Rear() {
if(isEmpty()){
return -1;
}
int index=(rear==0)?elem.length-1:rear-1;
return elem[index];
}
public boolean isEmpty() {
return rear==front;
}
public boolean isFull() {
return (rear+1)%elem.length==front;
}
}
用队列实现栈
void push(int x)
将元素 x 压入栈顶。int pop()
移除并返回栈顶元素。int top()
返回栈顶元素。boolean empty()
如果栈是空的,返回true
;否则,返回false
。
class MyStack {
public int useSize;
Queue<Integer> qu1;
Queue<Integer> qu2;
public MyStack() {
qu1=new LinkedList<>();
qu2=new LinkedList<>();
}
public void push(int x) {
if(!qu1.isEmpty()){
qu1.offer(x);
}else if(!qu2.isEmpty()){
qu2.offer(x);
}else{
qu1.offer(x);
}
useSize++;
}
public int pop() {
if(empty()){
return -1;
}
if(!qu1.isEmpty()){
int curSize=qu1.size();
for(int i=0;i<curSize-1;i++){
qu2.offer(qu1.poll());
}
useSize--;
return qu1.poll();
}else{
int curSize=qu2.size();
for(int i=0;i<curSize-1;i++){
qu1.offer(qu2.poll());
}
useSize--;
return qu2.poll();
}
}
public int top() {
if(empty()){
return -1;
}
if(!qu1.isEmpty()){
int curSize=qu1.size();
int ret=-1;
for(int i=0;i<curSize;i++){
ret=qu1.poll();
qu2.offer(ret);
}
return ret;
}else{
int curSize=qu2.size();
int ret=-1;
for(int i=0;i<curSize;i++){
ret=qu2.poll();
qu1.offer(ret);
}
return ret;
}
}
public boolean empty() {
return useSize==0;
}
}
用栈实现队列
void push(int x)
将元素 x 推到队列的末尾int pop()
从队列的开头移除并返回元素int peek()
返回队列开头的元素boolean empty()
如果队列为空,返回true
;否则,返回false
class MyQueue {
Stack<Integer> s1;
Stack<Integer> s2;
public MyQueue() {
s1=new Stack<>();
s2=new Stack<>();
}
public void push(int x) {
s1.push(x);
}
public int pop() {
if(empty()){
return -1;
}
if(s2.empty()){
while(!s1.empty()){
s2.push(s1.pop());
}
}
return s2.pop();
}
public int peek() {
if(empty()){
return -1;
}
if(s2.empty()){
while(!s1.empty()){
s2.push(s1.pop());
}
}
return s2.peek();
}
public boolean empty() {
return s1.empty() && s2.empty();
}
}
实现最小栈
MinStack()
初始化堆栈对象。void push(int val)
将元素val推入堆栈。void pop()
删除堆栈顶部的元素。int top()
获取堆栈顶部的元素。int getMin()
获取堆栈中的最小元素。
class MinStack {
private Stack<Integer> s;
private Stack<Integer> minStack;
public MinStack() {
s=new Stack<>();
minStack=new Stack<>();
}
public void push(int val) {
s.push(val);
if(!minStack.empty()){
int peekV=minStack.peek();
if(val<=peekV){
minStack.push(val);
}
}else{
minStack.push(val);
}
}
public void pop() {
if(!s.empty()){
int popV=s.pop();
int peekVMin=minStack.peek();
if(popV==peekVMin){
minStack.pop();
}
}
}
public int top() {
if(!s.empty()){
return s.peek();
}
return 0;
}
public int getMin() {
if(!minStack.empty()){
return minStack.peek();
}
return 0;
}
}