《剑指offer》------栈/队列专题


用两个栈实现队列

//需要考虑S2是否为空  
import java.util.Stack;

public class Solution {
    Stack<Integer> stack1 = new Stack<Integer>();
    Stack<Integer> stack2 = new Stack<Integer>();
    
    //队列的压入就是s1的压入数据  
    public void push(int node) {
        stack1.push(node);
    }
    
    //弹出借助于S1/s2 两个   弹出需要考虑队列是否为空
    public int pop() {
        if(size()!=0){
            if(stack2.empty()){                //若s2为空  则需要把s1的元素全部压入s2再输出
                while(!stack1.empty())
                    stack2.push(stack1.pop());
            }
            return stack2.pop();               //若s2不为空 则直接输出
        }else{
            System.out.println("队列为空,不能执行出队操作");
            return -1;
        }
    }
    //队列的大小  队列为空则说明 s1/s2均为空
    public int size(){
        return stack1.size()+stack2.size();
    }
}



用两个队列实现一个栈





import java.util.*;
/**
 * 使用LinkedList表示队列    所以队列从尾入队  q1.addLast(e)   从头出队q1.removeFirst()
 * @author 多多
 *
 * @param <E>
 */
public class MyStack<E> {
	LinkedList<E>  q1=new LinkedList<E>();    //队列1
	LinkedList<E>  q2=new LinkedList<E>();    //队列2
	
	//入栈操作 即入队
	public void push(E e) {
		q1.addLast(e);    //从尾部入队
	}
	
	//出栈操作:  非空队列的n-1个压入空队列  剩余的第n个出队   总有一个队列为空
	public E pop() {
		if(size()!=0) {                              //判断栈是否为空
			if(!q1.isEmpty()) {
				putN_1ToAnother();           //非空队列的n-1个压入空队列
				return q1.removeFirst();     //剩余的第n个出队 (从对头出队)
			}else {
				putN_1ToAnother(); 
				return q2.removeFirst(); 
			}
		}else {
			System.out.println("栈为空,无法执行出栈操作");
			return null;
		}
	}
	
	// 非空队列的n-1个压入空队列
	private void putN_1ToAnother() {
		if(!q1.isEmpty()) {               //若q2为空 则从q1中移动前n-1个
			while(q1.size()>1) {  
				q2.addLast(q1.removeFirst());
			}
		}else {
			while(q2.size()>1) {      //若q1为空 则从q2中移动前n-1个
				q1.addLast(q2.removeFirst());
			}
		}
	}

	//判断栈是否为空
	public int size() {
		return q1.size()+q2.size();
	}
}







包含min函数的栈



方法1: 每次都存入

import java.util.Stack;
 
public class Solution {
 
    private Stack<Integer> stackDate;
    private Stack<Integer> stackMin;
     
    public Solution(){
        stackDate = new Stack<>();
        stackMin = new Stack<>();
    }
    public void push(int node) {
        stackDate.push(node);
        if(stackMin.isEmpty()){
            stackMin.push(node);
        }else if(node <= stackMin.peek()){
            stackMin.push(node);
        }
    }
     
    public void pop() {
         if(stackDate.isEmpty()){
            throw new RuntimeException("This stack is empty!");
         }
         if(stackDate.peek() == stackMin.peek()){
             stackMin.pop();
         }
         stackDate.pop();
    }
     
    public int top() {
        if(stackDate.isEmpty()){
            throw new RuntimeException("This stack is empty!");
         }
        int value = stackDate.pop();
         if(value == stackMin.peek()){
             stackMin.pop();
         }
        return value;
    }
     
    public int min() {
        if(stackMin.isEmpty()){
            throw new RuntimeException("This stack is empty!");
        }else{
            return stackMin.peek();
        }
    }
}

方法2:只存入比之前小的元素

import java.util.Stack;
 
public class Solution {
 
    private Stack<Integer> stackDate;
    private Stack<Integer> stackMin;
     
    public Solution(){
        stackDate = new Stack<Integer>();
        stackMin = new Stack<Integer>();
    }
    public void push(int node) {
        stackDate.push(node);
        if(stackMin.isEmpty()){
            stackMin.push(node);
        }else if(node <= stackMin.peek()){
            stackMin.push(node);
        }
    }
     
    public void pop() {
         if(stackDate.empty()){
            throw new RuntimeException("This stack is empty!");
         }
         if(stackDate.peek() == stackMin.peek()){   //相同则一起弹出
             stackMin.pop();
         }
         stackDate.pop();     //否则只是弹出数据栈
    }
     
    public int top() {        //获取栈顶元素
        if(stackDate.isEmpty()){
            throw new RuntimeException("This stack is empty!");
         }
        int value = stackDate.pop();
         if(value == stackMin.peek()){
             stackMin.pop();
         }
        return value;
    }
     
    public int min() {
        if(stackMin.isEmpty()){
            throw new RuntimeException("This stack is empty!");
        }else{
            return stackMin.peek();
        }
    }
}






栈的压入 ,弹出序列





方法1:   Stack结构辅助

import java.util.ArrayList;
import java.util.Stack;
public class Solution {
    public boolean IsPopOrder(int [] pushA,int [] popA) {
        if(pushA.length==0 || popA.length==0|| pushA.length!=popA.length)
            return false;
      
        Stack<Integer> s=new Stack<Integer>();
        int index=0;                       //pop数组的下标
        for(int i=0;i<pushA.length;i++){
            s.push(pushA[i]);            //压入元素
            //判断  当s非空 且栈顶元素等于pop[index]时则弹出
            while(!s.empty() && s.peek()==popA[index]){
                s.pop();
                index++;
            }
        }
        
        return s.empty();               //正常则全部弹出 为空 否则为不正确的输出序列
    }
}
//注意一个地方:
while(index<popA.length && s.peek()==popA[index]){    //这个就是防止两个数组均对应输出完毕 出现栈为空 却要弹出的情况
                s.pop();
                index++;
            }





滑动窗口的最大值:

给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。


方法1 :时间O(n2)              两个for截取特定区间比较储存  
import java.util.ArrayList;
public class Solution {
    public ArrayList<Integer> maxInWindows(int [] num, int size)
    {
        //采用时间复杂度为O(n2)的笨办法
        ArrayList<Integer> list=new ArrayList<Integer>();
        if(num==null || num.length==0 || size<=0 || size> num.length)
            return list;
        int len=num.length;
        for(int i=0;i<len-size+1;i++){
            int max=Integer.MIN_VALUE;
            for(int j=i;j< i+size; j++){    //注意这个区间截取范围
                if(max< num[j])
                    max=num[j];
            }
            list.add(max);
        }
        return list;
    }
}
方法2 :时间O(n)   空间O(n)    采用队列的思想

import java.util.*;
public class Solution {
    public ArrayList<Integer> maxInWindows(int [] num, int size)
    {
        ArrayList<Integer> list=new ArrayList<Integer>();
        if(num==null || num.length==0 || size<=0 || size> num.length)
            return list;
        int len=num.length;
        //采用队列的思想 入队一个出队一个
        Queue<Integer>  q=new LinkedList<Integer>();
        int max=Integer.MIN_VALUE;
        //对于前size个元素  直接一次入队列
        for(int i=0;i<size;i++){
            q.add(num[i]);
            if(max <num[i])
                max=num[i];
        }
        list.add(max);
        //之后每次弹出一个 就进入一个 并在其中取最大值
        for(int i=size;i<len;i++){
            q.poll();
            q.add(num[i]);
            max=Integer.MIN_VALUE;
            for(Integer n: q){
                if(max< n)
                    max=n;
            }
            list.add(max);
        }
        return list;
    }
}


方法3 :时间,空间均为O(n)   采用“双端队列”的思想
原则:
  *     对新来的元素k,将其与双端队列中的元素相比较
  *     1)前面比k小的,直接移出队列(因为不再可能成为后面滑动窗口的最大值了!),
  *     2)前面比k大的X,比较两者下标,判断X是否已不在窗口之内,不在了,直接移出队列
  *     队列的第一个元素是滑动窗口中的最大值


import java.util.*;
public class Solution {
    public ArrayList<Integer> maxInWindows(int [] num, int size)
    {
        ArrayList<Integer> list=new ArrayList<Integer>();
        if(num==null || num.length==0 || size<=0 || size> num.length)
            return list;
        int len=num.length;
        //采用队列的思想 入队一个出队一个
        LinkedList<Integer>  q=new LinkedList<Integer>();  //队列存储的是下标
        for(int i=0;i<len;i++){   
            //从后面依次弹出队列中比当前num值小的元素 则当前队列首元素即为当前窗口的最大值
            while(!q.isEmpty() && num[q.peekLast()]<= num[i]){     //注意队列不为空的判断!!因为第一次是没有元素的,会主动跳过两个判断
                q.pollLast();
            }
            //当前窗口首元素位置移出当前窗口 则删除首元素
            while(!q.isEmpty() && i-q.peekFirst()>size-1){
                q.pollFirst();
            }
            q.addLast(i);    //将每一个num值入队
            if(size!=0 && i>=size-1){        //当i >=size-1时才开始写入窗口最大值
                list.add(num[q.peekFirst()]);
            }
        }
        return list;
    }
}  

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值