算法与数据结构-栈与队列 讲解与java代码实现

1.栈的基本知识

这里写图片描述这里写图片描述这里写图片描述这里写图片描述这里写图片描述这里写图片描述这里写图片描述

2.例题

1.返回栈最小元素

这里写图片描述这里写图片描述这里写图片描述

import java.util.Stack;
//可查询最小值的栈设计
public class Solution {
    Stack<Integer> stackData=new Stack<Integer>();//保存元素
    Stack<Integer> stackMin=new Stack<Integer>();//保存从stackData的栈中元素的最小值集合
    public void push(int node) {
        stackData.push(node);

        if(stackMin.isEmpty()||node<stackMin.peek()){
            stackMin.push(node);
        }else{
            stackMin.push(stackMin.peek());
        }
    }

    public void pop() {
        stackData.pop();
        stackMin.pop();
    }

    public int top() {
        return stackData.peek();
    }

    public int min() {
        return stackMin.peek();
    }
}

2.双栈队列

编写一个类,只能用两个栈结构实现队列,支持队列的基本操作(push,pop)。
给定一个操作序列ope及它的长度n,其中元素为正数代表push操作,为0代表pop操作,保证操作序列合法且一定含pop操作,请返回pop的结果序列。
测试样例:
[1,2,3,0,4,0],6
返回:[1,2]
这里写图片描述这里写图片描述这里写图片描述

import java.util.*;
//双栈队列练习题
public class TwoStack {
    Stack<Integer> stackPush=new Stack<Integer>();
    Stack<Integer> stackPop=new Stack<Integer>();

    public int[] twoStack(int[] ope, int n) {
        int index=0;
        for(int i=0;i<n;i++){
            int cur=ope[i];
            if(cur==0){
                ope[index++]=pop();
            }else{
                push(cur);
            }
        }
        int[] result=new int[index];
        for(int i=0;i<index;i++){
            result[i]=ope[i];
        }

        return result;
    }

    public void push(int p){
        stackPush.push(p);
    }

    public int pop(){
       if(stackPop.isEmpty()==true){
           while(stackPush.isEmpty()==false){
               stackPop.push(stackPush.pop());
           }
       }
       return stackPop.pop();
    }
}

3.栈逆序

这里写图片描述

实现一个栈的逆序,但是只能用递归函数和这个栈本身的pop操作来实现,而不能自己申请另外的数据结构。
给定一个整数数组A即为给定的栈,同时给定它的大小n,请返回逆序后的栈。
测试样例:
[4,3,2,1],4
返回:[1,2,3,4]
这里写图片描述这里写图片描述

import java.util.*;
//不使用额外的数据结构,使用递归函数完成栈的反转
//使用数组表示栈结构,一个整数变量n表示栈的大小;因为是栈,所以只能访问数组最后一个元素即栈顶元素,用A[n-1]表示
public class StackReverse {

    public int[] reverseStack(int[] A, int n) {
        if(n==0){
            return A;
        }
        int bottom=getBottom(A,n);
        n--;
        reverseStack(A,n);
        A[n]=bottom;

        return A;
    }
    //返回栈底元素
    public int getBottom(int[] A,int n){
        int result=A[n-1];
        n--;
        //数组第一个元素为栈底元素
        if(n==0){
            return result;
        }
        int bottom=getBottom(A,n);
        A[n-1]=result;
        return bottom;
    }

}

4.双栈排序

这里写图片描述这里写图片描述
请编写一个程序,按升序对栈进行排序(即最大元素位于栈顶),要求最多只能使用一个额外的栈存放临## 标题 ##时数据,但不得将元素复制到别的数据结构中。
给定一个int[] numbers(C++中为vector&ltint>),其中第一个元素为栈顶,请返回排序后的栈。请注意这是一个栈,意味着排序过程中你只能访问到第一个元素。
测试样例:
[1,2,3,4,5]
返回:[5,4,3,2,1]

import java.util.*;
//双栈排序
public class TwoStacks {
    public ArrayList<Integer> twoStacksSort(int[] numbers) {
        int size=numbers.length;
        ArrayList<Integer> help=new ArrayList<Integer>();

        for(int index=0;index<size;index++){
            int cur=numbers[index];
            if(help.size()==0||cur<=help.get(help.size()-1)){
                help.add(cur);
                continue;
            }else{
               int count=0;
               while(help.size()>0&&cur>help.get(help.size()-1)){
                numbers[index]=help.get(help.size()-1);
                help.remove(help.size()-1);
                count++;
                index--;
                }
                help.add(cur);
                while(count>0){
                    help.add(numbers[++index]);
                    count--;
                }
            }
        }
        return help;
    }
}

5.滑动窗口练习题

这里写图片描述
这里写图片描述这里写图片描述

有一个整型数组 arr 和一个大小为 w 的窗口从数组的最左边滑到最右边,窗口每次向右边滑一个位置。 返回一个长度为n-w+1的数组res,res[i]表示每一种窗口状态下的最大值。 以数组为[4,3,5,4,3,3,6,7],w=3为例。因为第一个窗口[4,3,5]的最大值为5,第二个窗口[3,5,4]的最大值为5,第三个窗口[5,4,3]的最大值为5。第四个窗口[4,3,3]的最大值为4。第五个窗口[3,3,6]的最大值为6。第六个窗口[3,6,7]的最大值为7。所以最终返回[5,5,5,4,6,7]。
给定整形数组arr及它的大小n,同时给定w,请返回res数组。保证w小于等于n,同时保证数组大小小于等于500。
测试样例:
[4,3,5,4,3,3,6,7],8,3
返回:[5,5,5,4,6,7]

import java.util.*;
//滑动窗口最大值
public class SlideWindow {
    public int[] slide(int[] arr, int n, int w) {
        LinkedList<Integer> qmax=new LinkedList<Integer>();//双端队列保存数组小标,其中队列头保存着当前的最大值对应的下标
        int[] result=new int[n-w+1];
        int index=0;
        for(int i=0;i<n;i++){

            while(qmax.isEmpty()==false&&arr[qmax.peekLast()]<=arr[i]){
                qmax.pollLast();
            }
               qmax.addLast(i);
            //如果当前队头的元素不在窗口内了,就弹出
            if(qmax.peekFirst()==(i-w)){
                qmax.pollFirst();
            }

            if(i>=(w-1)){
                result[index++]=arr[qmax.peekFirst()];
            }
        }

        return result;

    }
}

6.数组变树

这里写图片描述
这里写图片描述

import java.util.*;
//数组变树
public class MaxTree {
    public int[] buildMaxTree(int[] A, int n) {
        //遍历数组,找到每个数左边第一个比它大的数,找到每个数右边第一个比它大的数,
        int left=-2,right=-2;
        int[] result=new int[n];

        for(int i=0;i<n;i++){
            left=getMax(A,i,true);
            right=getMax(A,i,false);

            if(left!=-2&&right!=-2){
                result[i]=A[left]<A[right]?left:right;
            }else {
                result[i]=left==-2?right:left;
                if(result[i]==-2){
                    result[i]=-1;
                }
            }
        }
        //两个值中最小值是它的父节点如果数组左右比它大的数都是null,那它就是根
        return result;
    }

    public int getMax(int[] A,int curIndex,boolean isLeft){
        int maxIndex=curIndex;
        if(isLeft==true){
           for(int i=curIndex-1;i>=0;i--){
            if(A[i]>A[maxIndex]){
                maxIndex=i;
                break;
                }
            }
        }else{
            for(int i=curIndex+1;i<=A.length-1;i++){

            if(A[i]>A[maxIndex]){
                maxIndex=i;
                break;
                }
            }
        }
        return maxIndex==curIndex?-2:maxIndex;

    }

}

3.JAVA tips

ArrayList 删除元素:remove(index);
双端队列LinkedList qmax = new LinkedList()
双端队列获取队列首个元素或者最后的元素 peekFirst() peekLast()
双端队列弹出队列首个元素 pollFirst() 弹出最尾元素 pollLast()
双端队列添加元素到队尾 addLast(X)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值