LeetCode刷题笔记(Minimum Size Subarray Sum)

今天刷了一道难度适中的题目,感觉还凑合,下面就来总结一下经验吧。

具体题目如下:

Given an array of n positive integers and a positive integer s, find the minimal length of a contiguous subarray of which the sum ≥ s. If there isn't one, return 0 instead.

Example: 

Input: s = 7, nums = [2,3,1,2,4,3]
Output: 2
Explanation: the subarray [4,3] has the minimal length under the problem constraint.
Follow up:
If you have figured out the O(n) solution, try coding another solution of which the time complexity is O(n log n). 

题意分析:

给定一个正整数数组和一个正数s,然后在该数组中找到元素之和≥s的最短连续子数组并返回最短连续子数组的长度,若没有这样的连续子数组,请返回0。如果你已经找到了O(n)的解决方法,请尝试编写时间复杂度为O(n log n)的其他解决方法。

解答如下:

方法一(滑动窗格法①)

用两个指针l,r分别指向左端,同时确保两指针构成的区间没有元素,然后将sum与s进行比较,当满足r+1 < nums.size() && sum < s时,右端指针r++且sum=sum+nums[r],否则l++且sum=sum-nums[l],紧接着再判断sum≥s,如果是的则执行minlen = min(minlen, r-l+1),直到l < nums.size()不满足时,跳出循环再判断if (minlen == nums.size()+1),如果满足则说明没有这样的连续子数组故返回0,否则返回所找的最短的连续子数组。

这里有几点需要注意:① l = 0,r = -1,是为了保证初始区间中没有元素。② 程序中用到了if else的嵌套,而不用两个if if 是为了避免本来sum<s加了以后sum>=s,此时再进行判断就会造成sum<s,那么对于后面记录最短连续子数组的长度的if是有影响的。③if(r+1 < nums.size() && sum < s),该判断中之所以加r+1 < nums.size()是为了防止右边界发生数组越界。随着r的增大,连续子数组始终处于前增后减的状态,但是当r+1 < nums.size()不满足时,连续子数组会处于前不增但后会减的状态,直至l < nums.size()不满足,此时r指向数组最后一个元素,l为nums.size()已发生越界,所构成的区间也不包含任何元素。

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        int l = 0;
        int r = -1;
        int sum = 0;
        int minlen = nums.size()+1;//为了避免数组本身就是最短连续子数组,所以这里不能与数组最大长度一样
        while(l < nums.size()){
            if(r+1 < nums.size() && sum < s) //r+1 < nums.size()防止数组越界
                sum +=  nums[++r];
            else                             //此处是不可以改成if的,否则会影响到下面那个if
                sum -=  nums[l++];
            if(sum >= s)
                minlen = min(minlen, r-l+1);
        }
        if (minlen == nums.size()+1)
            return 0;
        return minlen;
    }
};. 

提交后的结果如下:

 

方法二(滑动窗格法②)

用for循环向前遍历元素并进行累加,用while循环判断sum >= s是否满足,若满足则记录下该子连续数组的长度,且从该子数组的左端删除元素,直到sum >= s不满足时为止。

//时间复杂度:O(n) 
class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        int n = nums.size(), start = 0, sum = 0, minlen = nums.size()+1;
        for (int i = 0; i < n; i++) { 
            sum += nums[i]; 
            while (sum >= s) {   //不断减,直至不满足条件,这里不可以改为if
                minlen = min(minlen, i - start + 1);
                sum -= nums[start++];
            }
        }
        return minlen == nums.size()+1 ? 0 : minlen; //简化了if和else判读,如果minlen == nums.size()+1 满足,则选择0,如果minlen == nums.size()+1 不满足则选择minlen
    }
};

提交后的结果如下:

 

方法三(暴力解法①)

用两层for循环,遍历所有可能的连续子数组,逐一计算逐一排除,然后得到最终答案。

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        int sum = 0;
        int minlen = nums.size()+1;
        for (int i = 0; i < nums.size() ; i++) {
            for (int j = i; j < nums.size(); j++) {
                sum += nums[j];
                if(sum >= s )
                    minlen = min(minlen, j-i+1);

            }
            sum = 0;               //每次都必须清零,不然sum值会越来越大

        }
        if (minlen == nums.size()+1)
            return 0;
        return minlen;
    }
};

提交后的结果如下:

 

方法四(暴力解法②)

用三层for循环,其中最内层for循环用于计算连续子数组的和。三层for循环的解法可能会Time Limit Exceeded

// 时间复杂度: O(n^3)
// 空间复杂度: O(1)
class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
 
        assert(s > 0);
 
        int minlen = nums.size() + 1;
        for(int l = 0 ; l < nums.size() ; l ++)
            for(int r = l ; r < nums.size() ; r ++){
                int sum = 0;
                for(int i = l ; i <= r ; i ++)
                    sum += nums[i];
                if(sum >= s)
                    minlen = min(minlen, r - l + 1);
            }
 
        if(minlen == nums.size() + 1)
            return 0;
 
        return minlen;
    }
};

提交后的结果如下:

 

日积月累,与君共进,增增小结,未完待续。   

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值