(四)剑指offer 栈与队列篇

1.滑动窗口的最大值

题目

给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{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)队列的头元素是这个队列中最大的元素。
(2)每次放队列中存放元素之前都要判断,如果不比队尾元素小,删除队尾元素,再存放。
(3)要判断何时存放队头元素至结果集中,以及何时删除队头元素。

	/**
	 * 	滑动窗口的最大值
	 * @param num
	 * @param size
	 * @return
	 */
	public static ArrayList<Integer> maxInWindows(int[] num, int size) {
		ArrayList<Integer> result = new ArrayList<>();
		if(num.length == 0 || num.length < size || size <= 0)
			return result;
		LinkedList<Integer> qmax = new LinkedList<>();
		for(int i = 0; i < num.length; i++) {
			while(!qmax.isEmpty() && num[qmax.peekLast()] <= num[i])
				qmax.pollLast();
			qmax.add(i);
			if(qmax.getFirst() == i - size)
				qmax.pollFirst();
			if(i >= size - 1)
				result.add(num[qmax.getFirst()]);
		}
		return result;
	}

2.用两个栈实现队列

题目

用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。

答案

思路:太简单,就不说了。

	Stack<Integer> stack1 = new Stack<Integer>();
	Stack<Integer> stack2 = new Stack<Integer>();

	public void push(int node) {
		while(!stack2.empty())
			stack1.push(stack2.pop());
		stack1.push(node);
	}
	public int pop() {
		while(!stack1.empty())
			stack2.push(stack1.pop());
		return stack2.pop();
	}

3.包含min函数的栈

题目

定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。

答案

这道题也很简单,主要是实现min函数查找栈中的最小元素,且时间复杂度为1。对空间没有要求,所以可以借助额外空间。

思路:
定义两个栈,dataStackminStackdataStack用来保存数据,minStack用来存放最小数。
每次使用push函数存放数据的时候,首先将数据放在dataStack中,然后再判断minStack栈顶元素是否小于或者等于当前要存放的数据,如果不是,则将数据存放minStack,如果是,则将minStack的栈顶元素再次存放道minStack中,确保dataStackminStack的相同高度。

	Stack<Integer> dataStack = new Stack<>();
    Stack<Integer> minStack = new Stack<>();
	
    public void push(int node) {
        dataStack.push(node);
        if(minStack.empty() || minStack.peek() >= node) {
        	minStack.push(node);
        }else {
        	minStack.push(minStack.peek());
        }
    }
    
    public void pop() {
        dataStack.pop();
        minStack.pop();
    }
    
    public int top() {
        return dataStack.peek();
    }
    
    public int min() {
        return minStack.peek();
    }

4.栈的压入、弹出序列

题目

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)

答案

思路:
借用一个辅助栈,将压入序列逐一压入栈,每压入一个元素,都用栈顶元素与弹出序列从头比较,如果不相等则继续压入,如果相等,删除栈顶元素,弹出序列向后移动一位,再继续比较……
当整个程序结束,如果栈中还有元素,则该弹出序列不是这个栈的弹出序列,反之则是。

	/**
	 * 栈的压入、弹出序列
	 * @param pushA
	 * @param popA
	 * @return
	 */
	public boolean IsPopOrder(int[] pushA, int[] popA) {
		Stack<Integer> stack = new Stack<>();
		for(int i = 0, j = 0; i < pushA.length; i++) {
			stack.push(pushA[i]);
			while(!stack.empty() && stack.peek() == popA[j]) {
				stack.pop();
				j++;
			}
		}
		return stack.empty();
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yelvens

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值