209. Minimum Size Subarray Sum

209. 长度最小的子数组

给定一个含有 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组如果不存在符合条件的连续子数组,返回 0。

示例: 

输入: s = 7, nums = [2,3,1,2,4,3]
输出: 2
解释: 子数组 [4,3] 是该条件下的长度最小的连续子数组。

进阶:

如果你已经完成了O(n) 时间复杂度的解法, 请尝试 O(n log n) 时间复杂度的解法。

解法一:

//时间复杂度O(n), 空间复杂度O(1)
class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        int i = 0, j = 0;
        int sum = 0, res = INT_MAX;
        while(true) {
            if(sum >= s) {
                res = min(res, j - i);
                sum -= nums[i++];
            }
            else if(j == nums.size()) break;
            else sum += nums[j++];
        }
        return res == INT_MAX ? 0 : res;
    }
};

解法二:
引用:官方题解长度最小的子数组

//时间复杂度O(n), 空间复杂度O(n)
int minSubArrayLen(int s, vector<int>& nums)
{
    int n = nums.size();
    if (n == 0)
        return 0;
    int ans = INT_MAX;
    vector<int> sums(n + 1, 0); //size = n+1 for easier calculations
    //sums[0]=0 : Meaning that it is the sum of first 0 elements
    //sums[1]=A[0] : Sum of first 1 elements
    //ans so on...
    for (int i = 1; i <= n; i++)
        sums[i] = sums[i - 1] + nums[i - 1];
    for (int i = 1; i <= n; i++) {
        int to_find = s + sums[i - 1];
        auto bound = lower_bound(sums.begin(), sums.end(), to_find);
        if (bound != sums.end()) {
            ans = min(ans, static_cast<int>(bound - (sums.begin() + i - 1)));
        }
    }
    return (ans != INT_MAX) ? ans : 0;
}

解法一:

双指针法。i、j最初都指向首元素,sum代表子序列[i, j]的局部和。

在每次循环内,如果sum >= s,就向右移动i指针,同时更新sum和res;

如果sum < s,说明序列长度不够,此时向右移动j指针,同时更新sum,直到j == nums.size()且sum < s时返回res。

解法二:

题上要求时间为O(nlogn)的解法,看到对数就想到二分法。思路如下:

双重遍历数组。i为起始,在[i, nums.size() - 1]这些位置中二分查找,找出刚好使sum >= s的位置j。遍历以每一个i为起始的所有情况,对每一个i,二分查找的时间为O(n),总的时间就是O(nlogn)。

为了方便二分查找过程中快速得到任意子序列的和,可以事先建立一个前缀和数组sums,则子序列[i, j]的和为sums[j] - sums[i - 1](认为sums[-1]为0);

二分查找的前提条件是数组有序,而前缀和数组必然是增序的(题上条件有正整数)。

2020/01/11 00:12
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值