《剑指offer》面试题59:队列的最大值

题目:滑动窗口的最大值

给定一个数组和滑动窗口的大小,请找出所有滑动窗口的最大值。例如,输入数组{2,3,4,2,6,2,5,1}和数字3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}。

思路:

把可能成为最大值数字的下标放入双端队列deque,从而减少遍历次数。首先,所有在没有查看后面数字的情况下,任何一个节点都有可能成为某个状态的滑动窗口的最大值,因此,数组中任何一个元素的下标都会入队。关键在于出队,以下两种情况下,该下标对应的数字不会是窗口的最大值需要出队:(1)该下标已经在窗口之外,比如窗口长度为3,下标5入队,那么最大值只可能在下标3,4,5中出现,队列中如果有下标2则需要出队;(2)后一个元素大于前面的元素,那么前面的元素出对,比如目前队列中有下标3、4,data[3] = 50,data[4]=40,下标5入队,但data[5] = 70,则队列中的3,4都需要出队。

数组{2,3,4,2,6,2,5,1}的长度为3的滑动窗口最大值求解步骤如下

步骤    插入数字    滑动窗口    队列中的下标   最大值
1       2          2           0(2)          N/A          
2       3          2,3         1(3)          N/A   
3       4          2,3,4       2(4)          4   
4       2          3,4,2       2(4),3(2)     4   
5       6          4,2,6       4(6)          6   
6       2          2,6,2       4(6),5(2)     6   
7       5          6,2,5       4(6),6(5)     6   
8       1          2,5,1       6(5),7(1)     5

时间复杂度在o(n)~o(nk)之间,空间复杂度o(k)。

基于以上思路,java参考代码如下:

package chapter6;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;

public class P288_classMaxInSlidingWindow {
    public static List<Integer> maxInWindows(int[] nums,int size){
        if(nums==null||nums.length<size||size<0) return null;
        ArrayDeque<Integer> deque=new ArrayDeque<>();
        List<Integer> res=new ArrayList<>();
        for(int i=0;i<size;i++){
            while (!deque.isEmpty()&&nums[i]>=deque.peekLast())
                deque.pollLast();
            deque.addLast(i);
        }
        for(int i=size;i<nums.length;i++){
            res.add(nums[deque.peekFirst()]);//front is the max number.
            while (!deque.isEmpty()&&nums[i]>=nums[deque.peekLast()]){
                deque.pollLast();
            }
            if(!deque.isEmpty()&&i-deque.peekFirst()>=size){
                deque.pollFirst();
            }
            deque.addLast(i);
        }
        res.add(nums[deque.peekFirst()]);//the last number.
        return res;
    }

    public static void main(String[] args) {
        System.out.println(maxInWindows(new int[]{2,3,4,2,6,2,5,1},3));
    }
}

测试用例:

a.功能测试(输入数组的数字大小无序;输入数组的数字单调递增;输入数组的数字单调递减)。
b.边界值测试(滑动窗口的大小为0,1,等于输入数组的长度,大于输入数组的长度)。
c.特殊输入测试(输入数组为空)。

参考:

https://www.jianshu.com/p/95e4e819761b

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值