阅读该文章需要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:题目描述
实现一个特殊的栈,在实现栈的基本功能的基础上,再实现返
回栈中最小元素的操作。
【要求】
- pop、push、getMin操作的时间复杂度都是O(1)。
- 设计的栈类型可以使用现成的栈结构。
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:赶紧学习