手写数组大根堆(每次先判断即将加入的新值是不是比前k个元素最大值大)(否则再判断上一个窗口的最大值是否被移出)(否则再遍历当前窗口,找出最大值) 滑动窗口的最大值 Leetcode100

手写数组大根堆

这道题 也直接验证了我的想法:对于二维数组来说,如果想要交换两个数组的内容的话,只要改变指针的指向即可,例如:

		int[] tem = heapArr[cur];
        heapArr[cur] = heapArr[parent];
        heapArr[parent]= tem;

对一维数组适用吗?

自己有时间试一下

代码:


 class Solution {
        public int[] maxSlidingWindow(int[] nums, int k) {

            PriorityQueue<Integer> q = new PriorityQueue<>((o1, o2) -> o1 - o2);{

                class heap{
                    int size = 0;
                    int[][] heapArr;

                    private heap(int capacity){     // 不要用 size ,easy 混淆,之前就错在,多写了一句 this.size = size;

                        this.heapArr = new int[capacity+1][2];
                    }

                    public boolean add(int[] numsi){
                        if(size > heapArr.length){
                            return false;
                        }
                        heapArr[++size] = numsi;
                        up(size);
                        return true;
                    }

                    private void up(int cur){
                        while((cur>>1) >= 1){
                            int parent  = cur>>1;
                            if( heapArr[parent][0] < heapArr[cur][0] ){
                                int[] tem = heapArr[cur];
                                heapArr[cur] = heapArr[parent];
                                heapArr[parent]= tem;
                                cur = parent;
                            }else{
                                break;
                            }
                        }
                    }


                    public int[] pop(){
                        int[] returnVal = heapArr[1];
                        heapArr[1] = heapArr[size];
                        size--;
                        Down(size);
                        return returnVal;
                    }

                    private void Down(int size){
                        int cur = 1;
                        while((cur<<1) <= size){
                            int child = cur<<1;
                            if((child+1) <= size && heapArr[child+1][0] > heapArr[child][0]){
                                child++;
                            }

                            if( heapArr[cur][0] < heapArr[child][0]){  // 55行
                                int[] tem = heapArr[cur];
                                heapArr[cur] = heapArr[child];
                                heapArr[child] = tem;
                                cur = child;
                            }else{
                                break;  // 怎么少了break呢,太大意
                            }
                        }
                    }


                    public int[] peek(){
                        return heapArr[1];

                    }

                }//end class heap
                if(nums.length == 0 || k == 1){
                    return nums;
                }

                int[] res = new int[nums.length - k +1];
                heap myheap = new heap(nums.length+1);
                for(int i=0; i<k; i++){
                    myheap.add(new int[]{nums[i],i});
                }

                res[0] = myheap.peek()[0];

                for(int i=k; i<nums.length; i++){

                    myheap.add(new int[]{nums[i],i});

                    if(nums[i] > myheap.peek()[0]){
                        res[i-k+1] = nums[i];
                    }else{
                        while(myheap.peek()[1] <= i-k ){
                            myheap.pop();
                        }

                        res[i-k+1] = myheap.peek()[0];
                    }
                }

                return res;

            }


        }
    }

思路

首先要遍历一下第一个滑动窗口内的所有元素,找出第一个滑动窗口内的最大值

然后:
// 欲求当前窗口里的最大值,
// 就要先判断:
// a. 新加入的值 是否比上一个窗口最大值大,若是,则当前窗口里的最大值即:新加入的值
// b. 否则再判断:待移除的值 是否是上一个窗口的最大值,若不是,则当前窗口里的最大值即:上一窗口最大值
// c. 否则说明上一个窗口的最大值已被移出,就只能遍历当前窗口内所有元素找出最大值

题目

在这里插入图片描述

代码及注释

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
       //首先要遍历一下第一个窗口内的所有元素,找出第一窗口内的最大值
       //然后:
       
        // 欲求当前窗口里的最大值,
        // 就要先判断:
        // a. 新加入的值 是否比上一个窗口最大值大,若是,则当前窗口里的最大值即:新加入的值
        // b. 否则再判断:待移除的值 是否是上一个窗口的最大值,若不是,则当前窗口里的最大值即:上一窗口最大值
        // c. 否则说明上一个窗口的最大值已被移出,就只能遍历当前窗口内所有元素找出最大值
        if (k == 0) return new int[0];
        int res[] = new int[nums.length - k + 1];   // 记录每一窗口的最大值
        for (int i = 0; i + k - 1 < nums.length; i++) {      // i 代表当前正在求第 i 个滑动窗口内的最大值,res[1] 保存的是第一个滑动窗口内的最大值。res[2]是第二个窗口内的最大值
            // 第 i 层循环的作用就是 求第 i 个滑动窗口内的最大值(从第0个滑动窗口开始) 。
            if (i > 0 && nums[i-1 + k] > res[i-1])  // res[i-1]为上一个滑动窗口内的最大值,i-1+k即向后再走k步就走到了要判断的新值的位置。  新值比上一窗口最大值大,返回 新值
                res[i] = nums[i-1 + k];
            else if (i > 0 && nums[i - 1] < res[i - 1]) // 若新值比上一窗口最大值小 且 待移除窗口的值比上一窗口最大值小(即 被移出窗口的不是上个窗口的最大值),则当前窗口的最大值 就是 上一个窗口的最大值
                res[i] = res[i - 1];
            else {   // 否则说明上一个窗口的最大值已被移出,就只能遍历当前窗口内所有元素找出最大值(下标从第 i 到 第 i+k-1 )
                int max = Integer.MAX_VALUE + 1;    // MAX_VALUE + 1 就取到了Integer范围内的 最小值,不是最大值哦
                for (int j = i; j <= i + k -1; j++) {
                    max = Math.max(max, nums[j]);
                    res[i] = max;       // 第一轮循环时:遍历前k个元素,找出第一个窗口里的最大值, 以k=3 为例,res[0] 保存着前3个数中的最大数
                }
            }
        }
        return res;
    }
}

笨方法 (通过双端队列Deque自己通过while循环实现一个递增的单调队列)

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {

        if(nums.length == 0 || k==0){
            return new int[0];
        }
        
        int[] res = new int[nums.length - k + 1];
        Deque<Integer> deq = new LinkedList<>();
        
        for(int i =0 ; i < k ; i++){
            while(!deq.isEmpty() && nums[i] > deq.peekLast()){
                deq.removeLast();
            }
            deq.addLast(nums[i]);
        }
        int index = 0;
        res[index++] = deq.peekFirst();
        
        for(int i = k; i< nums.length; i++){
            if( !deq.isEmpty() && deq.peekFirst() == nums[i-k]){    // 这一轮要滚出滑动窗口的元素nums[i-k] 就是该窗口的最大值
                deq.removeFirst();
            }
            while (( !deq.isEmpty() && nums[i] > deq.peekLast())){  // 通过移出比新加入窗口的元素 小的元素, 找到新加入窗口的元素应该在的位置
                deq.removeLast();
            }
            deq.addLast(nums[i]);   // 在这位置加入 新加入窗口的元素
            res[index++] = deq.peekFirst(); // 保存这一个串口的最大值(即对首元素)
        }

        return res;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

雄狮少年

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

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

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

打赏作者

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

抵扣说明:

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

余额充值