1. 栈(stack)
1.1概念
自己的理解:一种线性表,只能从一端插入,删除元素,遵循先进后出的原则;
标准定义:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。
压栈:栈的插入操作叫做压栈;
出栈:也称弹栈,栈的删除操作叫做出栈;
1.2 栈的实现
//利用顺序表实现
public class MyStack {
int [] array;
int size;
MyStack(){
//不考虑扩容问题
this.array=new int[100];
this.size=0;
}
public void push(int val){
this.array[size++]=val;
}
public int pop(){
return array[--size];
}
public int peek(){
return array[size-1];
}
public boolean isEmpty(){
return size==0;
}
public int size(){
return size;
}
}
2.队列(queue)
2.1概念
队列:只允许在一端进行插入操作,在另一端进行删除操作的顺序表,遵循先进先出原则;
入队列:进行插入操作的一端称为队尾
出队列:进行删除操作的一端称为队头
2.2 实现
class Node{
Node next;
int val;
Node(int val){
this.val=val;
}
}
//使用链表实现,数组实现的队列在进行出队列时时间复杂度太大
public class MyQueue {
private Node head;
private Node tail;
private int size;
MyQueue(){
this.head=null;
this.tail=null;
this.size=0;
}
public void offer(int val){
Node node=new Node(val);
if(head==null){
head=node;
}else{
tail.next=node;
}
tail=node;
size++;
}
public int poll(){
if(size==0){
throw new RuntimeException("队列为空!");
}
int v=head.val;
head=head.next;
//当队列中只有一个元素的时候,将尾结点置空
if(head==null){
tail=null;
}
size--;
return v;
}
public int peek(){
if(size==0){
throw new RuntimeException("队列为空");
}
return head.val;
}
public boolean isEmpty(){
return size==0;
}
public int size(){
return size;
}
}
2.3 循环队列
2.3.1实现:循环队列通常使用数组来实现
class MyCircularQueue {
// MyCircularQueue(k): 构造器,设置队列长度为 k 。
// Front: 从队首获取元素。如果队列为空,返回 -1 。
// Rear: 获取队尾元素。如果队列为空,返回 -1 。
// enQueue(int value): 向循环队列插入一个元素。如果成功插入则返回真。
// deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
// isEmpty(): 检查循环队列是否为空。
// isFull(): 检查循环队列是否已满。
private final int []queue;
private int size;
private int FrontIndex;
private int rearIndex;
/** Initialize your data structure here. Set the size of the queue to be k. */
public MyCircularQueue(int k) {
this.queue=new int[k];
this.size=0;
this.FrontIndex=0;
this.rearIndex=0;
}
/** Insert an element into the circular queue. Return true if the operation is successful. */
public boolean enQueue(int value) {
if(this.size==this.queue.length){
return false;
}
this.queue[rearIndex]=value;
this.rearIndex++;
size++;
if(this.rearIndex==this.queue.length){
this.rearIndex=0;
}
return true;
}
/** Delete an element from the circular queue. Return true if the operation is successful. */
public boolean deQueue() {
if(this.size==0){
return false;
}
size--;
this.FrontIndex++;
if(FrontIndex==this.queue.length){
FrontIndex=0;
}
return true;
}
/** Get the front item from the queue. */
public int Front() {
if(size==0){
return -1;
}
return this.queue[FrontIndex];
}
/** Get the last item from the queue. */
public int Rear() {
if(size==0){
return -1;
}
int index=this.rearIndex-1;
if(index==-1){
index=this.queue.length-1;
}
return this.queue[index];
}
/** Checks whether the circular queue is empty or not. */
public boolean isEmpty() {
return this.size==0;
}
/** Checks whether the circular queue is full or not. */
public boolean isFull() {
return this.size==this.queue.length;
}
}
3.面试题
1.力扣 20题(有效的括号)
链接
给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
示例 1:
输入: “()”
输出: true
示例 2:
输入: “()[]{}”
输出: true
示例 3:
输入: “(]”
输出: false
示例 4:
输入: “([)]”
输出: false
示例 5:
输入: “{[]}”
输出: true
来源:力扣(LeetCode)
class Solution {
public boolean isValid(String s) {
if(s.isEmpty()){
return false;
}
char [] c=s.toCharArray();
Deque<Character> Stack=new LinkedList<>();
for (char c1:c) {
switch (c1){
case '(':
case '[':
case '{':
Stack.push(c1);
break;
default:
//一定是右括号
if(Stack.isEmpty()){
return false;
}
if(!compare(Stack.pop(),c1)){
return false;
}
}
}
if(Stack.isEmpty()){
return true;
}
return false;
}
private boolean compare(char pop, char c1) {
if(pop=='['&&c1==']'){
return true;
}
if(pop=='('&&c1==')'){
return true;
}if(pop=='{'&&c1=='}'){
return true;
}
return false;
}
}
力扣225. 用队列实现栈
链接
push(x) – 元素 x 入栈
pop() – 移除栈顶元素
top() – 获取栈顶元素
empty() – 返回栈是否为空
来源:力扣(LeetCode)
import java.util.LinkedList;
import java.util.Queue;
//使用队列实现栈
// push(x) -- 元素 x 入栈
//pop() -- 移除栈顶元素
// top() -- 获取栈顶元素
//empty() -- 返回栈是否为空
public class Stack {
private Queue<Integer>queue;
Stack(){
this.queue=new LinkedList<>();
}
public void push(int val){
queue.add(val);
}
public int pop(){
int size=queue.size();
for(int i=0;i<size-1;i++){
Integer integer=queue.remove();
queue.add(integer);
}
return queue.remove();
}
public int top(){
int size=queue.size();
for(int i=0;i<size-1;i++){
Integer integer=queue.remove();
queue.add(integer);
}
Integer v=queue.remove();
queue.add(v);
return v;
}
public boolean empty(){
return queue.isEmpty();
}
}
力扣 232 用栈实现队列
链接
使用栈实现队列的下列操作:
push(x) – 将一个元素放入队列的尾部。
pop() – 从队列首部移除元素。
peek() – 返回队列首部的元素。
empty() – 返回队列是否为空。
来源:力扣(LeetCode)
import java.util.Deque;
import java.util.LinkedList;
class MyQueue {
/** Initialize your data structure here. */
private Deque <Integer>s1;
private Deque<Integer>s2;
public MyQueue() {
s1=new LinkedList<>();
s2=new LinkedList<>();
}
/** Push element x to the back of queue. */
public void push(int x) {
s2.push(x);
}
/** Removes the element from in front of queue and returns that element. */
public int pop() {
if(s1.isEmpty()){
while(!s2.isEmpty()){
Integer e = s2.pop();
s1.push(e);
}
}
return s1.pop();
}
/** Get the front element. */
public int peek() {
if(s1.isEmpty()){
while(!s2.isEmpty()){
Integer e = s2.pop();
s1.push(e);
}
}
return s1.peek();
}
/** Returns whether the queue is empty. */
public boolean empty() {
return s1.isEmpty()&&s2.isEmpty();
}
}
力扣 155.最小栈
链接
设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。
push(x) —— 将元素 x 推入栈中。
pop() —— 删除栈顶的元素。
top() —— 获取栈顶元素。
getMin() —— 检索栈中的最小元素
来源:力扣(LeetCode)
import java.util.Deque;
import java.util.LinkedList;
class MinStack {
//创建两个栈一个存储元素 一个存储最小值
Deque<Integer>stack1;
Deque<Integer>stack2;
MinStack(){
stack1=new LinkedList<>();
stack2=new LinkedList<>();
}
public void push(int val){
stack1.push(val);
//当stack2为空时,将val分别压入stack1和stack2(第一次压入)
//或者当stack2的栈顶元素大于等于val时压入stack2
//stack2.peek()>=val该处注意为什么有等号,一开始写的时候没写等号,运行出错了,问题就是压入相同的val值时没有等号就可能出错。
if(stack2.isEmpty()||stack2.peek()>=val){
stack2.push(val);
}
}
public void pop(){
int v=stack1.pop();
if(v==stack2.peek()){
stack2.pop();
}
}
public int top(){
return stack1.peek();
}
public int getMin(){
return stack2.peek();
}
}
力扣 622.设计循环队列
链接
设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。
循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。
你的实现应该支持如下操作:
MyCircularQueue(k): 构造器,设置队列长度为 k 。
Front: 从队首获取元素。如果队列为空,返回 -1 。
Rear: 获取队尾元素。如果队列为空,返回 -1 。
enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
isEmpty(): 检查循环队列是否为空。
isFull(): 检查循环队列是否已满。
来源:力扣(LeetCode)
class MyCircularQueue {
// MyCircularQueue(k): 构造器,设置队列长度为 k 。
// Front: 从队首获取元素。如果队列为空,返回 -1 。
// Rear: 获取队尾元素。如果队列为空,返回 -1 。
// enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
// deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
// isEmpty(): 检查循环队列是否为空。
// isFull(): 检查循环队列是否已满。
private final int []queue;
private int size;
private int FrontIndex;
private int rearIndex;
/** Initialize your data structure here. Set the size of the queue to be k. */
public MyCircularQueue(int k) {
this.queue=new int[k];
this.size=0;
this.FrontIndex=0;
this.rearIndex=0;
}
/** Insert an element into the circular queue. Return true if the operation is successful. */
public boolean enQueue(int value) {
if(this.size==this.queue.length){
return false;
}
this.queue[rearIndex]=value;
this.rearIndex++;
size++;
if(this.rearIndex==this.queue.length){
this.rearIndex=0;
}
return true;
}
/** Delete an element from the circular queue. Return true if the operation is successful. */
public boolean deQueue() {
if(this.size==0){
return false;
}
size--;
this.FrontIndex++;
if(FrontIndex==this.queue.length){
FrontIndex=0;
}
return true;
}
/** Get the front item from the queue. */
public int Front() {
if(size==0){
return -1;
}
return this.queue[FrontIndex];
}
/** Get the last item from the queue. */
public int Rear() {
if(size==0){
return -1;
}
int index=this.rearIndex-1;
if(index==-1){
index=this.queue.length-1;
}
return this.queue[index];
}
/** Checks whether the circular queue is empty or not. */
public boolean isEmpty() {
return this.size==0;
}
/** Checks whether the circular queue is full or not. */
public boolean isFull() {
return this.size==this.queue.length;
}
}