力扣-数组-长度最小的子数组-滑动窗口法

 

解法一:

嵌套循环暴力解法。设置一个指针从0开始向前走,每走一次都重复判断,将该指针位置的值不断向后相加,直到刚好大于或者等于目标值,将此段相加元素的长度存储下来。

指针每进步一次,都会得到一个长度,不断比较这些长度的到最小的值,如果没有的话返回0。

算法优化:每一次相加的时候都是从头加,这样无疑增加了很多时间复杂度,我们可否用一种方法将其的时间复杂度降低到o(n)级别呢?

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int sum=0;
        int sublength=0;
        int temp=9999;
        for (int i=0; i < nums.length; i++){
            sum=0;
            for (int j = i; j < nums.length; j++) {
                sum += nums[j];
                if (sum >= target) {//如果相加大于或者等于的时候就要停止了
                    sublength = j - i + 1;
                    if (temp > sublength) {
                        temp = sublength;
                    }
                    break;
                }
            }
        }
        if (temp == 9999){
            return 0;
        }
        return temp;
    }
}

解法二:

滑动窗口法!!!!

在本题中实现滑动窗口,主要确定如下三点:

  • 窗口内是什么?
  • 如何移动窗口的起始位置?
  • 如何移动窗口的结束位置?

窗口就是 满足其和 ≥ s 的长度最小的 连续 子数组。

窗口的起始位置如何移动:如果当前窗口的值大于s了,窗口就要向前移动了(也就是该缩小了)。

窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。

解题的关键在于 窗口的起始位置如何移动。

for(int i=0;i<nums.length;i++){
            sum+=nums[i];

            while(sum>=target){
                subLength=i-index+1;
                if(subLength<temp){
                    temp=subLength;
                }
            sum-=nums[index];
            index++;
            }

可以发现滑动窗口的精妙之处在于根据当前子序列和大小的情况,不断调节子序列的起始位置。从而将O(n^2)暴力解法降为O(n)。

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int sum=0;
        int index=0;
        int subLength=0;
        int temp=Integer.MAX_VALUE;
        for(int i=0;i<nums.length;i++){
            sum+=nums[i];

            while(sum>=target){
                subLength=i-index+1;
                if(subLength<temp){
                    temp=subLength;
                }
            sum-=nums[index];
            index++;
            }

/*
刨除最靠前的一位,继续比较如果有更短的就获取更短的。
这样就可以获得以index为开头按位的所有最短的长度。
index理论上是不断+1递增的,因为如果有一次index起始的相加,j一直走到结尾都没有找到满足条件的求和,那么index以后的数加到结尾只会比index更小。
每一次while循环最少需要进行一次操作,最多不超过目前存储的求和长度,因此我们认为while循环的次数是o(1)级别,综合起来为o(n)
*/

        }

        if(temp==Integer.MAX_VALUE){
            return 0;
        }else{
            return temp;
        }
    }
}

解法(滑动窗口):

算法思路:

研究的对象是一段连续的区间,因此可以使用滑动窗口思想来解决问题。  让滑动窗口满足:窗口内水果的种类只有两种。

做法:  右端水果进入窗口的时候,用哈希表统计这个水果的频次。这个水果进来后,判断哈希表的大小:

如果大小超过 2:说明窗口内水果种类超过了两种。那么就从左侧开始依次将水果划出窗口,直到哈希表的大小小于等于 2,然后更新结果;
如果没有超过 2,说明当前窗口内水果的种类不超过两种,直接更新结果 ret。
算法流程:

初始化哈希表 hash 来统计窗口内水果的种类和数量;
初始化变量:左右指针 left = 0,right = 0,记录结果的变量 ret = 0;
当 right 小于数组大小的时候,一直执行下列循环:
将当前水果放入哈希表中;
判断当前水果进来后,哈希表的大小:
如果超过 2:
将左侧元素滑出窗口,并且在哈希表中将该元素的频次减一;
如果这个元素的频次减一之后变成了 0,就把该元素从哈希表中删除;
重复上述两个过程,直到哈希表中的大小不超过 2;
更新结果 ret;
right++,让下一个元素进入窗口;
循环结束后,ret 存的就是最终结果。
 

复制的,还不会哈希表,以后再写

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值