lc题解239-日记篇

声名:问题描述来源于leetcode:

日记-lc题解

一、问题描述

239. 滑动窗口最大值

难度困难1904

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

返回 滑动窗口中的最大值

示例 1:

输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置                最大值
---------------               -----
[1  3  -1] -3  5  3  6  7       3
 1 [3  -1  -3] 5  3  6  7       3
 1  3 [-1  -3  5] 3  6  7       5
 1  3  -1 [-3  5  3] 6  7       5
 1  3  -1  -3 [5  3  6] 7       6
 1  3  -1  -3  5 [3  6  7]      7

示例 2:

输入:nums = [1], k = 1
输出:[1]

提示:

  • 1 <= nums.length <= 105
  • -104 <= nums[i] <= 104
  • 1 <= k <= nums.length

二、题解

思路1:

最平常的!

暴力解:

题解1:

class Solution {

    
    public int[] maxSlidingWindow(int[] nums, int k) {
        if (nums.length <= k){
            return maxNums(nums);
        }
        Queue<Integer> result = new LinkedList<>();
        List<Integer> list = new LinkedList<>();
        for (int i = 0; i < nums.length; i++) {
            if (list.size() < k){
                list.add(nums[i]);
            }else{// list.size() == k
                result.add(maxLinkedList(list));
                list.remove(0);
                list.add(nums[i]);
            }
        }
        
        result.add(maxLinkedList(list));
        return QueueToArray(result);
    }

    private int[] maxNums(int[] nums) {
        int maxNumber = nums[0];
        for (int i : nums) {
            if (maxNumber < i) maxNumber = i;
        }
        return new int[]{maxNumber};
    }

    private int[] QueueToArray(Queue<Integer> result) {
        int size = result.size();
        int[] resultArray = new int[size];
        for (int i = 0; i < size; i++) {
            resultArray[i] = result.poll();
        }
        return resultArray;
    }

    private Integer maxLinkedList(List<Integer> list) {

        int maxNum = list.get(0);
        for (int i : list) {
            if (maxNum < i){
                maxNum = i;
            }
        }

        return maxNum;
    }

}

结果:
image-1

再来:

题解2:

class MyQueue{
    private LinkedList<Integer> list = new LinkedList<>();
    public void addElement(Integer num){
        list.add(num);
    }
    public void addElementAndSort(Integer num){
        list.add(num);
        list.sort((num1,num2)->{
            return num1 - num2;
        });
    }
    public Integer getMaxNum(Integer deleteNode){
        Integer resultNum = list.get(list.size() - 1);
        list.removeFirstOccurrence(deleteNode);
        return resultNum;
    }
    public int size(){
        return list.size();
    }
    public int maxNum(){
        return list.get(list.size() - 1);
    }
}
class Solution {
   public int[] maxSlidingWindow(int[] nums, int k) {
        if (k == 1) return nums;
        if (nums.length <= k) return maxNums(nums);
        MyQueue myQueue = new MyQueue();
        Queue<Integer> resultQueue = new LinkedList<>();
        myQueue.addElement(nums[0]);
        for (int index = 1; index < nums.length; index++) {
            if (myQueue.size() == k){
                resultQueue.add(myQueue.getMaxNum(nums[index - k]));
            }

            if (nums[index] >= myQueue.maxNum()){
                myQueue.addElement(nums[index]);
            }else {
                myQueue.addElementAndSort(nums[index]);
            }
        }
        resultQueue.add(myQueue.maxNum());
        return resultArray(resultQueue);
    }

    private int[] resultArray(Queue<Integer> resultQueue) {
        int size = resultQueue.size();
        int[] resultNums = new int[size];
        for (int i = 0; i < size; i++) {
            resultNums[i] = resultQueue.poll();
        }
        return resultNums;
    }


    private int[] maxNums(int[] nums) {
        int maxNum = nums[0];
        for (int num : nums) {
            if (maxNum < num) maxNum = num;
        }
        return new int[]{maxNum};
    }
}

这个结果果然还是不行,关键是寻找将容器里的元素排序的算法优化,还是卡在第37个案例中。排序部分其实可以用二分排序来优化一下

题解3:

个人优化算法(排序部分)

class Solution {

    
   public int[] maxSlidingWindow(int[] nums, int k) {
    public int[] maxSlidingWindow(int[] nums, int k) {
        if (k == 1) return nums;//如果是1则直接返回
        if (nums.length <= k) return maxNums(nums);
        List<Integer> indexList = new LinkedList<>();
        int maxIndex = -1;
        for (int index = 0; index < nums.length; index++) {
            if (index + k > nums.length) break;//如果到了边界值那么就已经到尽头了,直接结束
            if (index <= maxIndex){//如果最大值索引在左索引右边,那么nums[maxIndex]除了和右边界的值没有确定,其他的均确定了
                if (nums[maxIndex] <= nums[index + k - 1]){//只需要比较右边界的值
                    maxIndex = index + k -1;
                }
                indexList.add(maxIndex);
                continue;
            }
            maxIndex = index;//此时的最大值索引是在[index,index+k)之间,所以要将maxIndex更新,才可以参与循环
            for (int innerIndex = index; innerIndex < index + k; innerIndex++) {
                if (nums[maxIndex] <= nums[innerIndex]) maxIndex = innerIndex;
            }
            indexList.add(maxIndex);

        }

        return maxArray(indexList,nums);
    }

    private int[] maxArray(List<Integer> indexList, int[] nums) {
        int[] result = new int[indexList.size()];
        int resultIndex = 0;
        for (int index : indexList) result[resultIndex++] = nums[index];
        return result;
    }

    private int[] maxNums(int[] nums) {
        int maxNum = nums[0];
        for (int num : nums) {
            if (maxNum < num) maxNum = num;
        }
        return new int[]{maxNum};
    }
}

运行:
在这里插入图片描述

又想到了还有一个思路:就是自定义一个容器对选取最大元素进行优化获取最大元素的时间,下面是该容器的属性:

  • 容器最大可以装k个元素node
  • 容器每个元素的属性有:order_by_insertTime、val、order_byVal
  • 有序性:按照val的大小排序
  • 对于相同val的元素,其排序也有细节要求;
  • 容器有添加元素的方法add(node)
  • 容器有删除元素的方法,是指删除添加时间最早的元素remove()
  • 容器有获取最大val的元素的val的方法getMaxVal()
  • 添加元素的方法是insert(node):将node添加到指定的位置,以保持有序性
  • 删除前会调用remove方法

这样子就可以将k个元素放进去,获取最大的出来了,但是感觉还是复杂的没最优,但是还是去实现一下:

我们可以遍历一次nums数组,当添加到k个元素时,便调用下该容器的getMaxVal()方法,将获取到的val用队列queue保存;接着循环继续时,再容器添加一个元素node,那么就先调用容器的remove方法将最先添加的元素删除,再将新的元素insert(node)进来,接着便再将最大元素返回,queue.add(容器.getMaxVal());

当循环走到nums最后一个数值后那么结束循环;

接着将queue的值抽到数组里返回
但是这个思路还是有点难实现的,于是又搁置了。。。

题解4:

public class Solution {

    public int[] maxSlidingWindow(int[] nums, int k) {
        if (k == 1) return nums;
        if (k >= nums.length) return maxNums(nums);
        int[] resultNums = new int[nums.length - k + 1];
        MyQueue myQueue = new MyQueue();

        for (int i = 0; i < k; i++) {
            myQueue.add(nums[i]);
        }
        int index = 0;
        resultNums[index++] = myQueue.peek();
        for (int i = k; i < nums.length; i++) {//这里面会为resultNums更新nums.lengh-k个元素
            //删除元素,如果nums[i - k]是最大值时,那么肯定是要干掉这个元素的,
            // 如果不是最大值,那么myQueue里根本不可能存在nums[i - k],因为都被add方法干掉了
            myQueue.pop(nums[i - k]);
            myQueue.add(nums[i]);
            resultNums[index++] = myQueue.peek();
        }
        return resultNums;
    }
    private int[] maxNums(int[] nums) {
        int maxNum = nums[0];
        for (int num : nums) {
            if (maxNum < num) maxNum = num;
        }
        return new int[]{maxNum};
    }


}

class MyQueue{
    LinkedList<Integer> list = new LinkedList<>();

    //返回索引为0的元素值
    int peek(){
        return list.peek();
    }

    void add(int val){
        //保证最前面的最大
        while (!list.isEmpty() && val > list.getLast()){
            list.removeLast();
        }
        list.add(val);
    }

    void pop(int val){
        if (!list.isEmpty() && val == list.peek()) list.pop();
    }
}

心得:

可以使用一个容器保存一系列节点,规定第一个节点的值最大,每次添加val的节点时需要删除一部分小值的节点,这么删除呢?是从元素列表的末尾向头部的方向遍历,一旦小于或等于val,那么就删除,直到遍历到比val更大的节点就退出删除操作,然后就挂在节点列表尾部。

另外,一开始就先得往容器处理前k个元素。然后才可以遍历nums[k]后面的元素,每次遍历都会对容器的首元素进行判断,判断是不是要删除的nums[index - k]元素。一开始xin麒会想到比如说有如[5,3,4,2,1,1,1,1,1,1,1,1],k = 5时,会不会删除到3这个元素呢?这个是不会发生的,因为它在添加操作时就已经被干掉了。在与nums[index - k]比较时,容器里根本就没有3这个元素。

注意:MyQueue的pop的参数类型是int不是包装类Integer,具体是什么原因呢?是lc官网的jdk版本不对还是什么呢?还是说在jdk8中有自动拆箱但是因为官网不是jdk8导致的呢?xin麒打算蹲一个有缘人解答,或者后面有时间再去敲打下背后的原因。。。

test:

public class Solution {
   
    public int[] maxSlidingWindow(int[] nums, int k) {
        if (k == 1) return nums;
        if (k >= nums.length) return maxNums(nums);
        int[] resultNums = new int[nums.length - k + 1];
        MyQueue myQueue = new MyQueue();

        for (int i = 0; i < k; i++) {
            myQueue.add(nums[i]);
        }
        int index = 0;
        resultNums[index++] = myQueue.peek();
        for (int i = k; i < nums.length; i++) {//这里面会为resultNums更新nums.lengh-k个元素
            //删除元素,如果nums[i - k]是最大值时,那么肯定是要干掉这个元素的,
            // 如果不是最大值,那么myQueue里根本不可能存在nums[i - k],因为都被add方法干掉了
            myQueue.pop(nums[i - k]);
            myQueue.add(nums[i]);
            resultNums[index++] = myQueue.peek();
        }
        return resultNums;
    }
    private int[] maxNums(int[] nums) {
        int maxNum = nums[0];
        for (int num : nums) {
            if (maxNum < num) maxNum = num;
        }
        return new int[]{maxNum};
    }

}

class MyQueue{
    LinkedList<Integer> list = new LinkedList<>();

    //返回索引为0的元素值
    Integer peek(){
        return list.peek();
    }

    void add(Integer val){
        //保证最前面的最大
        while (!list.isEmpty() && val > list.getLast()){
            list.removeLast();
        }
        list.add(val);
    }

    void pop(int val){
        if (!list.isEmpty() && val == list.peek()) list.pop();
    }
}

上面的是可以通过

下面的不行:

public class Solution {
   
    public int[] maxSlidingWindow(int[] nums, int k) {
        if (k == 1) return nums;
        if (k >= nums.length) return maxNums(nums);
        int[] resultNums = new int[nums.length - k + 1];
        MyQueue myQueue = new MyQueue();

        for (int i = 0; i < k; i++) {
            myQueue.add(nums[i]);
        }
        int index = 0;
        resultNums[index++] = myQueue.peek();
        for (int i = k; i < nums.length; i++) {//这里面会为resultNums更新nums.lengh-k个元素
            //删除元素,如果nums[i - k]是最大值时,那么肯定是要干掉这个元素的,
            // 如果不是最大值,那么myQueue里根本不可能存在nums[i - k],因为都被add方法干掉了
            myQueue.pop(nums[i - k]);
            myQueue.add(nums[i]);
            resultNums[index++] = myQueue.peek();
        }
        return resultNums;
    }
    private int[] maxNums(int[] nums) {
        int maxNum = nums[0];
        for (int num : nums) {
            if (maxNum < num) maxNum = num;
        }
        return new int[]{maxNum};
    }

   
}

class MyQueue{
    LinkedList<Integer> list = new LinkedList<>();

    //返回索引为0的元素值
    Integer peek(){
        return list.peek();
    }

    void add(Integer val){
        //保证最前面的最大
        while (!list.isEmpty() && val > list.getLast()){
            list.removeLast();
        }
        list.add(val);
    }

    void pop(Integer val){
        if (!list.isEmpty() && val == list.peek()) list.pop();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值