左神算法笔记(四)——队列和栈

题目一:用数组结构实现队列和栈

难度相当于一面第一道题的难度
队列结构:先入先出FIFO
栈结构:先入后出
实现栈:设置一个指针index,起始位置指向0的位置,读取一个数据则将数据放到数组【0】的位置,然后index++,之后新进来一个数则index++,取出数则index–。同时注意index的取值范围为0–size-1.
用数组实现栈

public static class ArrayStack{
	private Integer[] arr;
	private Integer size;
	
	public ArrayStack(int initSize){
		if(initSize<0){
			throw new IllegalArgumentException("The init size is less than 0");
		}
		arr = new Integer[initSize];
		size = 0;
	}
	//如果数组现在长度为0,那么返回空,如果不为0,现在数组中有值,则将最后一个数据取出。
	public Integer peek(){
		if(size ==0){
			return null
		}
		return arr[size-1];
	}
	//将数据存入栈中,如果存入数据的数目超过了栈(数组)本身的长度,则会弹出异常
	//没有超过时则将新读取的数据存放到数组之中,同时将size加一
	public void push(int obj){
		if(size == arr.length){
			throw new ArrayIndexOutOfBoundsException("the queue is full");
		}
		arr[size++] = obj;
	}
	//将数据弹出栈,只要长度不为0,那么就弹出最后一个数据,同时将size的长度减一
	public void pop(){
		if(size == 0){
			throw new ArrayIndexOutOfBoundException("the queue is empty");
		}
		return arr[--size];
	}
}

数组表示队列

public static class ArrayQueue{
	private Integer[] arr;
	private Integer size;
	private Integer first;
	private Integer last;
	
	public ArrayQueue(int initSize){
		if(initSize<0){
			throw new IllegalArgumentException("the init size is less than 0");
		}
			arr  = new Integer[initsize];
			size = 0;
			first = 0;
			last = 0;
	}

	public Integer peek(){
		if(size == 0){
			return null
		}
		return arr[first];
	}
	//数据读取到数组中跟数据读出是相同的操作,这里的精髓在于将last和first指针重新归零,这样数组长度不变,形成一个圆的循环,使得数据可以不断的存储和取出,形成一个队列。
	public void push(int obj){
		if(size == arr.length){
			throw new ArrayIndexOutOfBoundsException("the queue is full");
		}
		size++;
		arr[last] = obj;
		last = last == arr.length-1 ? 0 : last+1;
	}
	//将数据读取出,读取的过程是将first指针进行向后移动,同时进行first是否到了最底端,如果到了则归零,不到则继续向后读取数据
	public Integer poll(){
		if(size == 0){
			throw new ArrayIndexOutOfBoundsException("the queue is empty");
		}
		size--;
		int tmp = first;
		first = first == arr.length-1 ? 0 : first+1;
		return arr[tmp];
	}
}

数组实现栈结构和队列结构,需要自己可以顺利编写出来,需要多加练习。

题目二:实现一个特殊的栈,实现栈的基础功能的同时,再返回栈中最小元素的操作

【要求】:pop,push,getmin操作时间复杂度都为O(1),设计的栈类型可以采用现成的栈结构。
个人理解:如果题目要求时间复杂度较小,而自己可以想到一种时间复杂度较大的方法,则可以尝试将空间复杂度增大而减少时间复杂度
本题一眼看过去觉得可以采用遍历的方法,可以寻找到栈中最小的元素,但是遍历的过程时间复杂度较高,复杂度为O(N),不符合要求,所以可以想办法提高空间复杂度,可以多创立一个数组或栈,第一个栈中可以用于存放基本的栈的功能,第二个栈中可以进行最大最小值的比较。

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

	public Mystack1(){
		this.stackData = new Stack<Integer>();
		this.stackMin = new Stack<Integer>();
	}
	//放入最小值堆栈中时,此处仅放置比当前最小值小的数值,另一种思路是如果当前数值大于目前最小值,则将最小值再次放入到数组之中,做到跟正常栈中数据数目相同,同时push和pop
	public void push(int newNum){
		if(this.stackMin.isEmpty()){
			this.stackMin.push(newNum);
		}else if(newNum<=this.getmin()){
			this.stackMin.push(newNum);
		}
		this.stackData.push(newNum);
	}
	//放入数据方式不同,因此最小值栈弹出数据方式也不同,先比较data栈中弹出数值和当前最小值是否相等, 不相等则不弹出,相等才弹出
	public int pop(){
		if(this.stackData.isEmpty()){
			throw new RuntimeException("your stack is empty");
		}
		int value = this.stackData.pop();
		if(value == this.getmin()){
			this.stackMin.pop();
		}
		return value;
	}
	
	public int getMin(){
		if(this.stackMin.isEmpty()){
			throw new RuntimeException("your stack is empty");
		}
		return this.stackMin.peek();
	}
}
		

题目三:队列结构实现栈结构/栈结构实现队列结构

队列结构实现栈结构:用两个队列,将先入的数据存储到另外一个队列之中,只剩下最后一个数据用于弹出。之后还要求弹出还是一样的将其他数据全部存储到另一个队列之中,只剩最后一个数据用于弹出。数据存储则按照队列的形式存储。
两个队列实现栈

public static class TwoQueuesStack{
	private Queue<Integer> queue;
	private Queue<Integer> help;

	private TwoQueuesStack(){
		queue = new LinkedList<Integer>();
		help = new LinkedList<Integer>();
	}

	public void push(int pushInt){
		queue.add(pushInt);
	}

	public int peek(){
		if(queue.isEmpty()){
			throw new RuntimeException("stack is empty");
		}
		while(queue.size()!=1){
			help.add(queue.poll());
		}
		int res = queue.poll();
		help.add(res);
		swap();
		return res;
	}

	public int pop(){
		if(queue.isEmpty()){
			throw new RuntimeException("stack is empty");
		}
		while(queue.size()>1){
			help.add(queue.poll());
		}
		int res = queue.poll();
		swap();
		return res;
	}
	//将两个队列进行名称互换,实现转换
	private void swap(){
		queue<Integer> tmp = help;
		help = queue;
		queue = tmp;
	}
}

题目四:猫狗队列

//定义一个父类,存在两个子类,猫和狗
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 PetEnterQueue{
	private Pet pet;
	private Long count;
	public PetEnterQueue(Pet pet,long count){
		this.pet = pet;
		this.count = count;
	}
	public Pet getPet(){
		return this.pet;
	}
	public long getCount(){
		return this.count;
	}
	public String getEnterPetType(){
		return this.pet.getPetType();
	}
}
//设置猫和狗的队列,在add的时候需要判断宠物类型,再放入对应的两个队列中。
public static class dogCatQueue{
	private Queue<PetEnterQueue> dogQ;
	private Queue<PetEnterQueue> catQ;
	private long count;

	public DogCatQueue(){
		this.dogQ = new linkedList<PetEnterQueue>();
		this.catQ = new linkedList<petEnterQueue>();
		this.count = 0;
	}
	public void add(Pet pet){
		if(pet.getPetType().equals("dog")){
			this.dogQ.add(new PetEnterQueue(pet,this.count++));
		}else if(pet.getPetType().equals("cat")){
			this.catQ.add(new PetEnterQueue(pet,this.count++));
		}else{
			throw new RuntimeException("err,not dog or cat");
		}
	}
	//由于队列的特性是先入先出,因此在这里判断队列中count值的大小,因为两个队列公用一个count,因此可以知道存入的顺序,再按照顺序依次读出就可以
	public Pet pollAll(){
		if(!this.dogQ.isEmpty()&&!this.catQ.isEmpty()){
	 		if(this.dogQ.peek().getCount()<this.catQ.peek().getCount()){
	 			return this.dogQ.poll().getPet();
 			}else{
 				return this.catQ.poll().getPet();
			}
			//只有当两个队列其中一个为空的时候才可能退出,跳转到下面
		}else if (!this.dogQ.isEmpty()){
			return this,dogQ.poll().getPet();
		}else if(!this.catQ.isEmpty()){
			return this.catQ.poll().getPet();
		}else{
			throw new RuntimeException("err");
		}
	}
	public Dog pollDog(){
		if(!this.isDogQueueEmpty()){
			return (Dog) this.dogQ.poll().getPet()}else{
			throw new RuntimeException("Dog queue empty");
		}
	}

	public Cat pollCat(){
		if(!this.isCatQueueEmpty(){
			return (Cat) this.catQ.poll().getPet();
		}else{
			throw new RuntimeException("cat queue is Empty"):
		}
	}
	public boolean isEmpty(){
		return this.dogQ.isEmpty() &&this.catQ.isEmpty();
	}
	public boolean isDogQueueEmpty(){
		return this.dogQ.isEmpty();
	}
	public boolean isCatQueueEmpty(){
		return this.catQ.isEmpty();
	}
}

猫狗问题中,可以采用三个队列,分别存储猫队列,狗队列和全部的宠物队列,上述做法只采用了两个队列,将两个队列同时计数,具有唯一性,因此省掉第三个总队列,将空间复杂度降低,时间复杂度相同。

发布了24 篇原创文章 · 获赞 6 · 访问量 505

猜你喜欢

转载自blog.csdn.net/qq_35065720/article/details/104141484