我要进大厂-算法-第三天(栈和队列拿下)

本文介绍了如何使用数组实现栈和队列,并展示了如何维护最小值栈,以及利用栈和队列实现彼此的功能。此外,还详细解释了猫狗队列的实现,以及转圈打印矩阵的方法。通过这些实例,深入理解数据结构的基本操作和设计思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

阅读该文章需要30分钟

一:数组实现栈、队列

前提知识:栈先进后出,队列先进先出。

1.1:数组实现栈
1.1.1:题目描述:

用数组结构实现大小固定的队列和栈

1.1.2:思路如下:
用数组存进来的数
用一个变量指明最后一个数的位置(尾标志)

push操作放入存的数据,尾标志向后移动一位
pop操作取出最后一位的数据,尾标志向前移动一位
1.1.3:Java代码
package xyz.fudongyang.basic.class_03.my;

public class Code_01_Array_To_Stack_Queue {

    public static class ArrayStack {
        private Integer[] arr;
        private Integer index;

        public ArrayStack(Integer size) {
            if (size < 1) {
                throw new IllegalArgumentException("The stack size do not less than 1");
            }
            this.arr = new Integer[size];
            this.index = 0;
        }

        public Integer pop() {
            if (index < 0) {
                throw new IllegalArgumentException("The stack is empty");
            }
            return arr[--index];
        }

        public void push(Integer req) {
            if (index >= arr.length) {
                throw new IllegalArgumentException("The stack is full");
            }
            arr[index++] = req;
        }

    }

    public static void main(String[] args) {
        ArrayStack arrayStack = new ArrayStack(20);
        arrayStack.push(1);
        arrayStack.push(2);
        arrayStack.push(3);
        System.out.println(arrayStack.pop());
        System.out.println(arrayStack.pop());
        System.out.println(arrayStack.pop());
        // 会报错
        System.out.println(arrayStack.pop());
    }

}

1.2:数组实现队列
1.2.1:思路
数组存放数据

维护一个size,记录数组中的元素个数

维护一个头标记,和尾标记。可以是个环,走到数组的最后一个元素就来到第一个元素

push操作,last放压入的数据,last位置向后移动一位,数组数据size+1
pop操作,弹出first位置的元素,first位置向后移动一位,数组数据size-1
1.2.2:代码如下
package xyz.fudongyang.basic.class_03.my;

public class Code_01_Array_To_Stack_Queue {


    public static class ArrayQueue {
        private final Integer[] arr;
        private Integer size;
        private Integer first;
        private Integer last;

        public ArrayQueue(int size) {
            if (size < 1) {
                throw new IllegalArgumentException("The stack size do not less than 1");
            }
            this.arr = new Integer[size];
            this.size = 0;
            this.first = 0;
            this.last = 0;
        }
        public Integer pop(){
            if (size <= 0){
                throw new IllegalArgumentException("error");
            }
            size--;
            int temp = first;
            first = first == arr.length-1 ? 0 : first+1;
            return arr[temp];
        }
        public void push(Integer req){
            if (size >= arr.length){
                throw new IllegalArgumentException("error");
            }
            arr[last] = req;
            size++;
            last = last == arr.length -1 ? 0 : last +1;
        }
    }

    public static void main(String[] args) {
        ArrayQueue arrayStack = new ArrayQueue(20);
        arrayStack.push(1);
        arrayStack.push(2);
        arrayStack.push(3);
        System.out.println(arrayStack.pop());
        System.out.println(arrayStack.pop());
        System.out.println(arrayStack.pop());
        System.out.println(arrayStack.pop());
    }

}

二:维护最小栈

2.1.1:题目描述

实现一个特殊的栈,在实现栈的基本功能的基础上,再实现返
回栈中最小元素的操作。

【要求】

  1. pop、push、getMin操作的时间复杂度都是O(1)。
  2. 设计的栈类型可以使用现成的栈结构。
2.1.2:思路如下
维护两个栈,一个是数据栈,一个是最小值栈

push操作:数据栈进入数据,如果当前压入数据比最小值栈顶小,则也压入数据到最小值栈
pop操作:弹出数据栈顶,如果数据栈顶元素等于最小值栈顶元素,则最小值栈也弹出
getMin操作:获取最小值栈顶的值
2.1.3:Java代码
package xyz.fudongyang.basic.class_03.my;

import java.util.Stack;

public class Code_02_GetMinStack {
	public static class MyStack1 {
		private Stack<Integer> stackData;
		private Stack<Integer> minStack;

		public MyStack1(){
			this.stackData = new Stack<>();
			this.minStack = new Stack<>();
		}

		public void push(Integer req){
		    if (minStack.isEmpty() || this.getmin() > req){
		        minStack.push(req);
            }
		    stackData.push(req);
        }

        public Integer pop(){
		    if (stackData.isEmpty()){
		        throw new IllegalArgumentException("error");
            }
            Integer pop = stackData.pop();
		    if (pop.equals(getmin())){
		        minStack.pop();
            }
		    return pop;
        }

        public Integer getmin(){
		    if (minStack.isEmpty()){
		        throw new IllegalArgumentException("error");
            }
		    return minStack.peek();
        }
	}

	public static class MyStack2 {
		private Stack<Integer> stackData;
		private Stack<Integer> stackMin;

		public MyStack2() {
			this.stackData = new Stack<Integer>();
			this.stackMin = new Stack<Integer>();
		}

		public void push(int newNum) {
			if (this.stackMin.isEmpty()) {
				this.stackMin.push(newNum);
			} else if (newNum < this.getmin()) {
				this.stackMin.push(newNum);
			} else {
				int newMin = this.stackMin.peek();
				this.stackMin.push(newMin);
			}
			this.stackData.push(newNum);
		}

		public int pop() {
			if (this.stackData.isEmpty()) {
				throw new RuntimeException("Your stack is empty.");
			}
			this.stackMin.pop();
			return this.stackData.pop();
		}

		public int getmin() {
			if (this.stackMin.isEmpty()) {
				throw new RuntimeException("Your stack is empty.");
			}
			return this.stackMin.peek();
		}
	}

	public static void main(String[] args) {
		MyStack1 stack1 = new MyStack1();
		stack1.push(3);
		System.out.println(stack1.getmin());
		stack1.push(4);
		System.out.println(stack1.getmin());
		stack1.push(1);
		System.out.println(stack1.getmin());
		System.out.println(stack1.pop());
		System.out.println(stack1.getmin());

		System.out.println("=============");

		MyStack1 stack2 = new MyStack1();
		stack2.push(3);
		System.out.println(stack2.getmin());
		stack2.push(4);
		System.out.println(stack2.getmin());
		stack2.push(1);
		System.out.println(stack2.getmin());
		System.out.println(stack2.pop());
		System.out.println(stack2.getmin());
	}

}

三:栈实现队列、队列实现栈

前提知识:栈先进后出,队列先进先出。

3.1:栈实现队列
3.1.1:思路如下:
用两个栈实现队列

第一个栈放进栈的数据,第二个栈放出栈的数据

第一个栈直接放数据,push操作

第二个栈负责peek、pop操作。当有其中一个操作的时候,从第二个栈直接弹出一个数据
若第二个栈无数据了,将第一个栈的数据依次压到第二个栈中,再返回。

若两个栈都无数据,抛异常
3.1.2:Java代码
package xyz.fudongyang.basic.class_03.my;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;

public class Code_03_StackAndQueueConvert {

	public static class TwoStacksQueue {
		// push 进去数据
		private final Stack<Integer> firstStack;
		// 消费数据
		private final Stack<Integer> secondStack;
		public TwoStacksQueue (){
			this.firstStack = new Stack<>();
			this.secondStack = new Stack<>();
		}

		public void push(Integer req){
			firstStack.push(req);
		}

		public Integer peek(){
			if (secondStack.isEmpty()){
				while (!firstStack.isEmpty()){
					secondStack.push(firstStack.pop());
				}
			}
			return secondStack.peek();
		}

		public Integer pop(){
			if (secondStack.isEmpty()){
				while (!firstStack.isEmpty()){
					secondStack.push(firstStack.pop());
				}
			}
			return secondStack.pop();
		}
	}



	public static void main(String[] args) {
		// stack->queue
		TwoStacksQueue twoStacksQueue = new TwoStacksQueue();
		twoStacksQueue.push(1);
		twoStacksQueue.push(2);
		twoStacksQueue.push(3);
		twoStacksQueue.push(4);
		System.out.println(twoStacksQueue.peek());
		System.out.println(twoStacksQueue.pop());
		System.out.println(twoStacksQueue.peek());
		System.out.println(twoStacksQueue.pop());
		System.out.println(twoStacksQueue.peek());
		System.out.println(twoStacksQueue.pop());
		System.out.println(twoStacksQueue.peek());
		System.out.println(twoStacksQueue.pop());
		
	}

}
3.2:队列实现栈
3.2.1:思路如下
用两个队列实现栈

第一个队列为数据队列,第二个队列为交换队列

push操作:进数据,均进入第一个队列

pop操作:出数据,将队列的最后一个值保留,其余值,存向第二个交换队列,
将第一个队列的最后一个值返回,此时第一个队列为空,交换第一个、第二个队列。

peek操作:出数据,将队列的最后一个值保留,其余值,存向第二个交换队列,
将第一个队列的最后一个值返回,此时第一个队列为空,
交换第一个、第二个队列,将返回值加入第一个队列中。
3.2.2:Java代码
package xyz.fudongyang.basic.class_03.my;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;

public class Code_03_StackAndQueueConvert {


	public static class TwoQueuesStack {
		// 生产
		private Queue<Integer> firstQueue;
		// 消费
		private Queue<Integer> secondQueue;

		TwoQueuesStack(){
			this.firstQueue = new LinkedList<>();
			this.secondQueue = new LinkedList<>();
		}

		public void push(Integer req){
			firstQueue.add(req);
		}

		public Integer peek(){
			if (firstQueue.isEmpty()){
				throw new RuntimeException("error");
			}
			while (firstQueue.size() != 1){
				secondQueue.add(firstQueue.poll());
			}
			// 将第一个队列的最后一个数据拿出来
			int res = firstQueue.poll();
			secondQueue.add(res);
			temp();
			return res;
		}

		public Integer pop(){
			if (firstQueue.isEmpty()){
				throw new RuntimeException("error");
			}
			while (firstQueue.size() != 1){
				secondQueue.add(firstQueue.poll());
			}
			// 将第一个队列的最后一个数据拿出来
			int res = firstQueue.poll();
			temp();
			return res;
		}

		public void temp(){
			Queue<Integer> temp;
			temp = firstQueue;
			firstQueue = secondQueue;
			secondQueue = temp;
		}

	}

	public static void main(String[] args) {

		// queue-stack
		TwoQueuesStack twoStacksQueue1 = new TwoQueuesStack();
		twoStacksQueue1.push(1);
		twoStacksQueue1.push(2);
		twoStacksQueue1.push(3);
		twoStacksQueue1.push(4);
		System.out.println(twoStacksQueue1.peek());
		System.out.println(twoStacksQueue1.pop());
		System.out.println(twoStacksQueue1.peek());
		System.out.println(twoStacksQueue1.pop());
		System.out.println(twoStacksQueue1.peek());
		System.out.println(twoStacksQueue1.pop());
		System.out.println(twoStacksQueue1.peek());
		System.out.println(twoStacksQueue1.pop());
	}

}

四:猫狗队列

4.1:题目描述

猫狗队列 【题目】 宠物、狗和猫的类如下:

public class Pet { 
    private String type;
	public Pet(String type) { 
        this.type = type; 
    }
	public String getPetType() { 
        return this.type;
    }
}
public class Dog extends Pet { 
    public Dog() { 
        super("dog"); 
    } 
}
public class Cat extends Pet {
    public Cat() {
        super("cat");
    } 
}

实现一种狗猫队列的结构,要求如下: 用户可以调用add方法将cat类或dog类的
实例放入队列中; 用户可以调用pollAll方法,将队列中所有的实例按照进队列
的先后顺序依次弹出; 用户可以调用pollDog方法,将队列中dog类的实例按照
进队列的先后顺序依次弹出; 用户可以调用pollCat方法,将队列中cat类的实
例按照进队列的先后顺序依次弹出; 用户可以调用isEmpty方法,检查队列中是
否还有dog或cat的实例; 用户可以调用isDogEmpty方法,检查队列中是否有dog
类的实例; 用户可以调用isCatEmpty方法,检查队列中是否有cat类的实例。

4.2:思路如下
宠物类的属性不够用,我们给他增加一个属性,叫做次序,也就是进入猫狗队列的次序,第一个,第二个······

维护一个猫队列,所有的猫都进猫队列
维护一个狗队列,所有的狗都进狗队列

push操作:如果是猫就进猫队列,如果是狗就进狗队列,宠物次序+1

popAll操作:如果猫狗队列都有宠物,判断猫狗队列中的队首,他们的次序大小,
较小的代表进入队列时间较早。则弹出。若其中一个队列为空,另外一个队列弹出宠物。

popDog操作:弹出狗队列队首元素

popCat操作:弹出猫队列队首元素

isEmpty操作:如果两个队列都不为空,则不为空
4.3:代码如下
package xyz.fudongyang.basic.class_03.my;

import sun.awt.image.ImageWatched;

import java.util.LinkedList;
import java.util.Queue;

public class Code_04_DogCatQueue {

	public static class Pet {
		private String type;

		public Pet(String type) {
			this.type = type;
		}

		public String getPetType() {
			return this.type;
		}
	}

	public static class Dog extends Pet {
		public Dog() {
			super("dog");
		}
	}

	public static class Cat extends Pet {
		public Cat() {
			super("cat");
		}
	}

	public static class EnterPet{
		private Pet pet;
		// 记录自己的次序
		private int count;

		public EnterPet(Pet pet,int count){
			this.pet = pet;
			this.count = count;
		}

		public Pet getPet(){
			return this.pet;
		}

		public int getCount(){
			return this.count;
		}

	}

	public static class DogCatQueue{
		private Queue<EnterPet> dogQueue;
		private Queue<EnterPet> catQueue;
		// 记录总次序
		private int count;

		public DogCatQueue(){
			this.dogQueue = new LinkedList<>();
			this.catQueue = new LinkedList<>();
			this.count = 1;
		}

		public void add(Pet pet){
			if (pet instanceof Cat){
				catQueue.add(new EnterPet(pet,count++));
			}else if (pet instanceof Dog){
				dogQueue.add(new EnterPet(pet,count++));
			}else {
				throw new RuntimeException("传的是什么牛马?");
			}
		}

		public Pet pollAll(){
			if (!dogQueue.isEmpty() && !catQueue.isEmpty()){
				if (dogQueue.peek().getCount() < catQueue.peek().getCount()){
					return dogQueue.poll().getPet();
				}else {
					return catQueue.poll().getPet();
				}
			}
			if (!dogQueue.isEmpty()){
				return dogQueue.poll().getPet();
			}
			return catQueue.poll().getPet();
		}

		public Dog pollDog(){
			if (dogQueue.isEmpty()){
				throw new RuntimeException("没狗了");
			}
			return (Dog) dogQueue.poll().getPet();
		}

		public Cat pollCat(){
			if (catQueue.isEmpty()){
				throw new RuntimeException("没猫了");
			}
			return (Cat) catQueue.poll().getPet();
		}

		public boolean isEmpty(){
			return dogQueue.isEmpty() && catQueue.isEmpty();
		}

		public boolean isDogQueueEmpty(){
			return dogQueue.isEmpty();
		}
	}

	public static void main(String[] args) {
		DogCatQueue test = new DogCatQueue();

		Pet dog1 = new Dog();
		Pet cat1 = new Cat();
		Pet dog2 = new Dog();
		Pet cat2 = new Cat();
		Pet dog3 = new Dog();
		Pet cat3 = new Cat();

		test.add(dog1);
		test.add(cat1);
		test.add(dog2);
		test.add(cat2);
		test.add(dog3);
		test.add(cat3);

		test.add(dog1);
		test.add(cat1);
		test.add(dog2);
		test.add(cat2);
		test.add(dog3);
		test.add(cat3);

		test.add(dog1);
		test.add(cat1);
		test.add(dog2);
		test.add(cat2);
		test.add(dog3);
		test.add(cat3);
		while (!test.isDogQueueEmpty()) {
			System.out.println(test.pollDog().getPetType());
		}
		while (!test.isEmpty()) {
			System.out.println(test.pollAll().getPetType());
		}
	}

}

五:转圈打印矩阵

5.1:题目描述

【题目】 给定一个整型矩阵matrix,请按照转圈的方式打印它。
例如: 1 2 3 4 5 6 7 8 9 10 11 12 13 14
15 16 打印结果为:1,2,3,4,8,12,16,15,14,13,9,
5,6,7,11, 10
【要求】 额外空间复杂度为O(1)。

5.2:解题思路
		/**
		 *		左上角
		 *		↓
		 * 		1	2	3	4
		 *
		 * 		5	6	7	8
		 *
		 * 		9	10	11	12
		 *
		 * 		13	14	15	16
		 *					↑
		 *					右下角
		 */
我们记录下来左上角、右下角的行和列坐标

我们按照这样打印:左到右(1、2、3)、右到下(4、8、12)、
下到左(16、15、14)、左到上(13、9、5)这是一圈,第二圈按照这个次序打印

如果长比宽高,我们只需打印行,左到右
如果宽比长高,我们只需打印列,上到下
5.3:Java代码
package xyz.fudongyang.basic.class_03.my;

import java.security.PublicKey;

public class Code_05_PrintMatrixSpiralOrder {

	public static void spiralOrderPrint(int[][] matrix) {
		/**
		 *		左上角
		 *		↓
		 * 		1	2	3	4
		 *
		 * 		5	6	7	8
		 *
		 * 		9	10	11	12
		 *
		 * 		13	14	15	16
		 *					↑
		 *					右下角
		 */
		// 行坐标 左上角
		int tR = 0;
		// 列坐标 左上角
		int tC = 0 ;
		// 行坐标 右下角
		int dR = matrix.length-1;
		// 列坐标 右下角
		int dC = matrix[0].length-1;
		while (tR <= dR && tC <= dC){
			printElement(tR++,tC++,dR--,dC--,matrix);
		}
	}

	private static void printElement(int tR,int tC,int dR,int dC,int[][] arr ){
		// 如果长比宽高
		if (tR <= dR && tC == dC){
			for (int i = tR; i <= dR; i++) {
				System.out.println(arr[i][tC]+"/t");
			}
		}else if (tR == dR && tC <= dC){
		// 如果宽比长高
			for (int i = tC; i <= dC; i++) {
				System.out.println(arr[tR][i]+"/t");
			}
		}else {
			int crrR = tR;
			int crrC = tC;
			while (crrR < dR){
				System.out.println(arr[crrC][crrR++]+"/t");
			}
			while (crrC < dC){
				System.out.println(arr[crrC++][crrR]+"/t");
			}
			while (crrR > tR){
				System.out.println(arr[crrC][crrR--]+"/t");
			}
			while (crrC > tC){
				System.out.println(arr[crrC--][crrR]+"/t");
			}

		}
	}


	public static void main(String[] args) {
		int[][] matrix = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 },
				{ 13, 14, 15, 16 } };
		spiralOrderPrint(matrix);

	}

}

六:放到最后

在这里插入图片描述
一群lsp:赶紧学习

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值