栈与队列

Stack栈的基本操作:
new Stack():创建一个空栈
push(E e):将元素压入栈,返回值为该元素
pop():将元素弹出栈,返回值为该元素
peek():返回栈顶元素,但是并不从栈中移除该元素
empty():测试栈是否为空,返回boolean值

可查询最值的栈问题

题目:
定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的min函数。

代码:

import java.util.Stack;

public class Solution {

    //定义两个栈结构,一个存储数据,一个存储最小值
    Stack<Integer> stackData = new Stack<Integer>();
    Stack<Integer> stackMin = new Stack<Integer>();

    //压入操作
    public void push(int node) {
        //数据栈直接压入
        stackData.push(node);
        //最小值栈做判断:是否为空,为空可以直接压入,不为空的情况需要比较当前元素与最小值栈栈顶元素值的大小
        if(!stackMin.empty()){
            if(stackMin.peek()<=node){
                stackMin.push(stackMin.peek());
            }else{
                stackMin.push(node);
            }
        }else{
            stackMin.push(node);
        }
    }

    //弹出操作
    public void pop() {

        if(stackData.empty()){
            throw new RuntimeException("Stack is empty");
        }else{
            stackData.pop();
            stackMin.pop();
        }

    }

    //获取栈顶元素
    public int top() {

        if(stackData.empty()){
            throw new RuntimeException("Stack is empty");
        }else{

            return stackData.peek();

        }

    }

    //获取最小元素
    public int min() {

        if(stackMin.empty()){
            throw new RuntimeException("Stack is empty");
        }else{

           return stackMin.peek();
        }

    }
}

双栈队列问题

题目:
编写一个类,只能用两个栈结构实现队列,支持队列的基本操作(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 count = 0;
        for(int i=0;i<n;i++){
            if(ope[i]==0){
               count++; 
            }

        }

        int[] result = new int[count];
        int j= 0;

        for(int i=0;i<n;i++){
            if(ope[i]!=0){
               push(ope[i]); 
            }else{
                result[j++] = pop();
            }

        }

        return result;


    }

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


    //保证两点:
    //每次倒入数据时stackPop栈中为空
    //stackPush倒数据的时候要一次性倒完
    public int pop(){
        if(stackPop.empty()&&stackPush.empty()){
            throw new RuntimeException("Queue is empty");
        }

        if(stackPop.empty()){

            while(!stackPush.empty()){
                stackPop.push(stackPush.pop());
            }

        }

        return stackPop.pop();
    }


}

栈的反转

题目:
实现一个栈的逆序,但是只能用递归函数和这个栈本身的pop操作来实现,而不能自己申请另外的数据结构。

给定一个整数数组A即为给定的栈,同时给定它的大小n,请返回逆序后的栈。

测试样例:
[4,3,2,1],4
返回:[1,2,3,4]

代码:

import java.util.*;

public class StackReverse {
    public int[] reverseStack(int[] A, int n) {
        //边界条件判定
        if(A==null||n==0){
            return null;
        }

        Stack<Integer> stack = new Stack<Integer>();
        //数组转栈
        for(int i=n-1;i>=0;i--){
            stack.push(A[i]);
        }

        reverse(stack);

        int j = 0;
        //栈转为数组
        while(!stack.empty()){
           A[j++] = stack.pop(); 
        }

        return A;

    }

    //逆序方法
    public void reverse(Stack<Integer> stack){

        //栈为空,直接返回
        if(stack.empty()){
            return;
        }

        //递归去除栈底元素,并重新压入
        int last = get(stack);
        reverse(stack);
        stack.push(last);

    }

    //返回栈底元素并删除
    public int get(Stack<Integer> stack){

        //弹出栈顶元素
        int result = stack.pop();

        //判断,如果此时为空,则上一步弹出的即为栈底元素
        if(stack.empty()){
            return result;
        }else{
            //last表示栈底元素
            int last = get(stack);
            //非栈底元素重新按照顺序压入栈中
            stack.push(result);
            return last;

        }
    }
}

双栈排序问题

题目:
请编写一个程序,按升序对栈进行排序(即最大元素位于栈顶),要求最多只能使用一个额外的栈存放临时数据,但不得将元素复制到别的数据结构中。

给定一个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) {
        //边界条件判定
        if(numbers==null||numbers.length==0){
            return null;
        }

        //定义临时栈,在临时栈中排序
        Stack<Integer> helpStack = new Stack<Integer>();

        //变量i代表当前栈顶
        int i = 0;
        int temp = 0;
        while(i<numbers.length){

            //如果临时栈为空,直接压入数据
            if(helpStack.empty()){
                helpStack.push(numbers[i]);
                i++;
            }else{
                //不为空的情况要进行比较,比较当前栈顶元素与临时栈顶元素的大小,
                //临时栈顶元素较小或等于的话直接压入数据
                //否则要先把临时栈中小于当前栈顶元素的元素先弹出,然后再压入当前栈顶元素,后续循环一样的步骤
                temp = numbers[i];
                i++;
                while(helpStack.peek()>temp){

                    numbers[--i] = helpStack.pop();
                    //有可能helpStack为空了,循环条件peek()会报错,所以这里检查一下,为空则跳出循环即可
                    if(helpStack.empty()){
                        break;
                    }

                }

                helpStack.push(temp);

            } 
        }

        ArrayList<Integer> list = new ArrayList<Integer>();
        while(!helpStack.empty()){
            list.add(helpStack.pop());
        }

        return list;
    }


}

滑动窗口问题

题目:
有一个整型数组 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) {
        //边界条件判定
        if(arr==null||w<=0){
            return null;
        }

        //构建双端队列,存储滑动窗口的最大值
        LinkedList<Integer> queue = new LinkedList<Integer>();
        //创建结果数组
        int[] result = new int[n-w+1];
        //创建结果数组递增下标
        int index = 0;

        //遍历循环数组
        for(int i=0;i<n;i++){

            //如果双端队列不为空,且当前窗口最新进入的值大于队列队尾的值,则删除队尾值,循环检查
            while(!queue.isEmpty()&&arr[queue.peekLast()]<=arr[i]){
                queue.pollLast();
            }

            //加入队尾
            queue.addLast(i);

            //队头的下标是否过期,过期就剔除
            if(queue.peekFirst()==(i-w)){
                queue.pollFirst();
            }


            //以此插入最大值
            if(i>=w-1){
                 result[index++] = arr[queue.peekFirst()]; 
            }

        }

        return result;


    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值