剑指Offer-面试题59-I:滑动窗口的最大值 双端队列法

这里是题目描述:剑指Offer-面试题59-I:滑动窗口的最大值

这道题我们直观上可以使用蛮力法,对所有可能的滑动窗口,遍历它们并求最小值。假设数组长度为n,滑动窗口尺寸为k,那么蛮力法的时间复杂度将是O(nk)。对于长度很长,尺寸较大的滑动窗口来说,时间开销很大,不能满足要求。

借助双端队列的解法

我们观察滑动窗口的移动规律可以得知,滑动窗口每向右移动一步,原窗口最左边的数字出窗口,原窗口最右边的数字进窗口。我们可以根据此规律,借助一个双端队列(相比与最基本队列的从一段入队列,另一端出队列,双端队列的两端都可以实现进队列。出队列的功能,java中有已经实现好的双端队列java.util.Deque)实现优化的解法:

使用双端队列存储当前及以后可能是滑动窗口最大值的元素,其中队头保存着当前滑动窗口最大值;当滑动窗口右移一步,若离开滑动窗口的元素值等于双端队列队头,则队头出队列;将新进入滑动窗口的元素值和队尾元素值比较,若它大于队尾值,则说明队尾值不再有机会成为某一位置的滑动窗口的最大值,队尾出队列,新进入滑动窗口的元素值继续和队尾比较,直到它小于等于队尾或双端队列为空,则从队尾进入双端队列

这样,通过使用双端队列,我们就把时间开销降到了O(n)

剑指Offer-面试题59-I:滑动窗口的最大值 双端队列法_第1张图片题解代码:

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        if(nums.length<=1)
        {
            return nums;
        }
        int window=0;
        int[] res=new int[nums.length-k+1];
        Deque<Integer> deque=new LinkedList<>(); //存储可能最大值的双端队列
        for(int i=0;i<k;i++)
        {
            enDeque(deque,nums[i]);
        }
        res[0]=deque.getFirst(); //队头就是当前滑动窗口的最大元素
        for(int i=k;i<nums.length;i++)
        {
            if(nums[i-k]==deque.getFirst())
            {
                deque.removeFirst(); //队头元素已经不在滑动窗口中,因此出队列
            }
            enDeque(deque,nums[i]);
            res[i-k+1]=deque.getFirst();
        }
        return res;
    }
    void enDeque(Deque<Integer> deque,int value)
    {
        while(deque.size()>0)
        {
            if(deque.getLast()<value) //移除比valu小的队尾元素
            {
                deque.removeLast();
            }
            else //队尾元素不比value小,停止比较和移除,跳出循环
            {
                break;
            }
        }
        deque.offerLast(value);
    }
}

时间复杂度:O(n)
空间复杂度:O(k)

你可能感兴趣的:(剑指offer编程题,队列,数据结构,queue,java)