剑指 Offer 59 - I. 滑动窗口的最大值

剑指 Offer 59 - I. 滑动窗口的最大值

【方法一 TreeMap】使用TreeMap<nums[i], cnt>,使用key来记录值,value记录这个值出现的次数,当窗口离开某个值的时候,先把它的计数-1,如果-到0就把这个值移除。

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        TreeMap<Integer, Integer> map = new TreeMap<Integer, Integer>((a, b) -> { return b - a; });
        int n = nums.length, m = n - k, i;
        if(n == 0) return new int[0];
        for(i = 0; i < k; i++){
            map.put(nums[i], map.getOrDefault(nums[i], 0) + 1);
        }
        int[] ans = new int[m + 1];
        ans[0] = map.firstKey();
        for(i = k; i < n; i++){
            int left = nums[i - k];
            int right = nums[i];
            if(map.get(left) == 1) map.remove(left);
            else map.put(left, map.get(left) - 1);
            map.put(right, map.getOrDefault(right, 0) + 1);
            ans[i - k + 1] = map.firstKey();
        }
        return ans;
    }  
}

【方法二 有序队列】使用有序队列来维护最大值以及后续的次大值,以样例为🌰

1,3,-1,-3,5, 3, 6, 7

一、首先将前三个加入队列

1:队列中只有1

3:从后往前检查队列,发现1比3小,让1出队列,原因是只要在这个窗口中还没滑到把3出走,那么最大值永远都是3,1对最大值已经没有任何帮助了,此时队列中只有3

-1:检查队列发现没有比-1小的,-1入队列,此时队列中有3,-1

这样第一个窗口的最大值就是队列的peek也就是3了。

二、滑动窗口的过程中,首先检查左侧丢掉的数是否为最大值,如果是最大值就把最大值出队列;然后检查右侧新加入的元素,入队在队列的什么地方。

第一次移动时:左侧1不在窗口内并且不是最大值,不用管;

右侧-3检查发现队列中没有<-3的,直接把-3入队列,此时队列中有3,-1,-3

更新完队列后最大值peek仍然是3.

第二次移动时:左侧3需要丢掉,同时因为它时最大值,此时要把队列的peek扔掉,

然后新加入了5,检查一遍队列,发现-3和-1都比5小,他们对后续的最大值已经不产生贡献了,所以直接出队列,并把5入队,此时队列中只剩5了,

同时最大值peek就是5了。

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        if(nums.length == 0) return new int[0];
        Deque<Integer> max = new LinkedList();
        int n = nums.length, m = n - k, i;
        int[] ans = new int[m + 1];
        for(i = 0; i < k; i++){
            while(!max.isEmpty() && max.peekLast() < nums[i]) max.pollLast();
            max.offer(nums[i]);
        }
        ans[0] = max.peek();
        for(i = k; i < n; i++){
            if(nums[i - k] == max.peek()) max.poll();
            while(!max.isEmpty() && max.peekLast() < nums[i]) max.pollLast();
            max.offer(nums[i]);
            ans[i - k + 1] = max.peek();
        }
        return ans;
    }
}

套y总的板子

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        int N = 100010;
        int tt = -1, hh = 0, n = nums.length;
        int[] q = new int[N];
        int[] ans = new int[n - k + 1];
        for (int i = 0, j = 0; i < n; i++) {
            while (tt >= hh && i - q[hh] + 1 > k) hh++;
            while (tt >= hh && nums[q[tt]] <= nums[i]) tt--;
            q[++tt] = i;
            if (i >= k - 1) ans[j++] = nums[q[hh]];
        }
        return ans;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值