剑指offer(Java实现)59 - 滑动窗口的最大值

本文介绍了一种高效的算法,用于解决滑动窗口最大值问题和队列最大值问题。通过使用双向队列存储数组下标,实现了O(1)时间复杂度的查找最大值操作,适用于数据流处理等场景。

滑动窗口的最大值-59-1

给定一个数组和滑动窗口的大小,请找出所有滑动窗口里的最大值。

例如,如果输入数组 [2, 3, 4, 2, 6, 2, 5, 1] 及滑动窗口的大小3,那么一共存在6个滑动窗口,它们的最大值分别为

[4, 4, 6, 6, 6, 5]。

注意:

  • 数据保证k大于0,且 k 小于等于数组长度。
样例
输入:[2, 3, 4, 2, 6, 2, 5, 1] , k=3
输出: [4, 4, 6, 6, 6, 5]

思路:

遍历数组,将数存放在双向队列中,并用 L,R 来标记窗口的左边界和右边界。队列中保存的并不是真的数,而是该数值对应的数组下标位置,并且数组中的数要从大到小排序。

如果当前遍历的数比队尾的值大,则需要弹出队尾值,直到队列重新满足从大到小的要求。

刚开始遍历时,L 和 R 都为0,有一个形成窗口的过程,此过程没有最大值,L 不动,R 向右移。

当窗口大小形成时,L和R一起向右移,每次移动时,判断队首的值的数组下标是否在 [L,R]中,如果不在则需要弹出队首的值,当前窗口的最大值即为队首的数。

class Solution {
    public int[] maxInWindows(int[] nums, int k) {
        int[] res = new int[nums.length - k + 1];
        LinkedList<Integer> queue = new LinkedList<>();
        for (int i = 0; i < nums.length; i++) {
            while (!queue.isEmpty() && nums[queue.peekLast()] <= nums[i])
                queue.pollLast();
            queue.addLast(i);
            if (queue.peek() <= i - k) queue.poll();
            if (i + 1 >= k) res[i + 1 - k] = nums[queue.peek()];
        }
        return res;
    }
}

队列的最大值-59-2

请定义一个队列并实现函数max得到队列里的最大值,要求函数max,push_back,pop_front的时间复杂度都是O(1)

思路:

利用一个双端队列来存储当前队列里的最大值以及之后可能的最大值

在定义题目要求功能的队列时,除了定义一个队列 data存储数值,还需额外用一个队列 maxmium存储可能的最大值。此外,还要定义一个数据结构,用于存放数据以及当前的 index值用于删除操作时确定是否删除 maxmium中最大值。

class Solution {
    
    private ArrayDeque<InternalData> data = new ArrayDeque<InternalData>();
    private ArrayDeque<InternalData> maximum = new ArrayDeque<InternalData>();

    private class InternalData {
        int number;
        int index;

        private InternalData(int number, int index) {
            this.number = number;
            this.index = index;
        }
    }

    private int curIndex;

    public void push_back(int number) {
        InternalData curData = new InternalData(number, curIndex);
        data.addLast(curData);

        while (!maximum.isEmpty() && maximum.getLast().number < number)
            maximum.removeLast();

        maximum.addLast(curData);

        curIndex++;  //别漏了这句
    }

    public void pop_front() {

        if (data.isEmpty()) {
            System.out.println("队列为空,无法删除!");
            return;
        }

        InternalData curData = data.removeFirst();

        if (curData.index == maximum.getFirst().index)
            maximum.removeFirst();
    }

    public int max() {

        if (maximum == null) {
            System.out.println("队列为空,无法删除!");
            return 0;
        }
        return maximum.getFirst().number;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值