剑指 Offer II 008. 和大于等于 target 的最短子数组

剑指 Offer II 008. 和大于等于 target 的最短子数组_第1张图片
思路:
(1)因为这道题要遍历子串来获得对应得子串长度,所以考虑滑动窗口时最直接得思路
时间复杂度:O(n),
空间复杂度:O(1)。

(2)因为没有负数,也可以采用二分法
时间复杂度:O(nlogn),
空间复杂度:O(n)。

(1)滑动窗口
这里得主要代码思路就是右指针不停在走,一直到第一次满足条件。之后左指针走,并逐步删除左边的元素,知道不满足条件后,右指针向右走,这样就能达到遍历符合要求的子串的效果了。

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums)
    {
        int low = 0;
        int high = 0;
        int res=INT_MAX;
        int sum = 0;
        int len = nums.size();
        for (high;high < len;high++)
        {
            sum += nums[high];
            while (low <= high && sum >= target)
            {res = min(res, high - low + 1);
            sum -= nums[low++];
        }
        }
        return res == INT_MAX ? 0 : res;
    }
};

(2)二分法
sums保存的是累计和,比如sums[2]表示nums前两个数据的和。lower_bound是现成的库和函数来为我们实现这里二分查找大于等于某个数的第一个位置的功能。

class Solution {
public:
    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 
        // sums[0] = 0 意味着前 0 个元素的前缀和为 0
        // sums[1] = A[0] 前 1 个元素的前缀和为 A[0]
        // 以此类推
        for (int i = 1; i <= n; i++) {
            sums[i] = sums[i - 1] + nums[i - 1];
        }
        for (int i = 1; i <= n; i++) {
            int target = s + sums[i - 1];
            auto bound = lower_bound(sums.begin(), sums.end(), target);
            if (bound != sums.end()) {
                ans = min(ans, static_cast<int>((bound - sums.begin()) - (i - 1)));
            }
        }
        return ans == INT_MAX ? 0 : ans;
    }
};

你可能感兴趣的:(算法,leetcode,数据结构)