前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >力扣209. 长度最小的子数组

力扣209. 长度最小的子数组

作者头像
ccf19881030
发布2023-05-09 10:06:05
2130
发布2023-05-09 10:06:05
举报
文章被收录于专栏:ccf19881030的博客ccf19881030的博客

209. 长度最小的子数组

题目描述

给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

示例 1:

代码语言:javascript
复制
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。

示例 2:

代码语言:javascript
复制
输入:target = 4, nums = [1,4,4]
输出:1

示例 3:

代码语言:javascript
复制
输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0

提示:

  • 1 <= target <= 10^9
  • 1 <= nums.length <= 10^5
  • 1 <= nums[i] <= 10^5

进阶:

  • 如果你已经实现 O(n) 时间复杂度的解法, 请尝试设计一个 O(n log(n)) 时间复杂度的解法。

解法1:暴力解法:

暴力法是最直观的方法。初始化子数组的最小长度为无穷大,枚举数组 nums nums 中的每个下标作为子数组的开始下标,对于每个开始下标 i,需要找到大于或等于 i 的最小下标 j,使得从nums[i] 到 nums[j] 的元素和大于或等于 s,并更新子数组的最小长度(此时子数组的长度是j−i+1)。 C++实现代码如下:

代码语言:javascript
复制
class Solution {
public:
    // 暴力法解决
    int minSubArrayLen(int target, vector<int>& nums) {
        if (nums.size() == 0) {
            return 0;
        }
        int ans = INT_MAX;
        for (int i = 0; i < nums.size(); i++) {
            int sum = 0;
            for (int j = i; j < nums.size(); j++) {
                sum += nums[j];
                if (sum >= target) {
                    ans = std::min(ans, j - i + 1);
                    break;
                }
            }
        }
        return ans == INT_MAX ? 0 : ans;
    }
};

暴力解法的时间复杂度是O(n^2),超时;空间复杂度为:O(1)

解法2:前缀和 + 二分查找

前缀和 + 二分查找的时间复杂度为:O(logn),空间复杂度为O(n)

代码语言:javascript
复制
class Solution2 {
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]
        // 以此类推
        // 计算nums数组的前缀和,注意前缀和数组的长度 = 原数组的长度nums.size() + 1
        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;
    }
};

解法3:滑动窗口解法:

滑动窗口时间复杂度为O(n),空间复杂度为O(1)

C++实现

代码语言:javascript
复制
class Solution {
public:
    // 滑动窗口解法
    int minSubArrayLen(int target, vector<int>& nums) {
        int n = nums.size();
        if (n == 0) return 0;
        // end指针先去找右边,找到了再收缩左边,end继续去找到更优解,找到收缩左边。
        int start = 0, end = 0;
        int ans = INT_MAX;
        // 终止指针指向窗口最右侧的位置索引
        int sum = 0;
        // end指针先去找右边
        while (end < n) {
            sum += nums[end];
            // 收缩左侧窗口(找到了再收缩左边)
            while (sum >= target) {
                // 计算更新子数组的最小长度
                ans = std::min(ans, end - start + 1);
                // 收缩左侧窗口
                sum -= nums[start];
                start++;
            }
            // end指针往右移动
            end++;
        }

        return ans == INT_MAX ? 0 : ans;
    }
};

C#实现:

代码语言:javascript
复制
public class Solution {
    public int MinSubArrayLen(int target, int[] nums) {
        if (nums.Length == 0) return 0;
            int start = 0, end = 0;
            int totalSum = 0;
            int ans = int.MaxValue;
            while (end < nums.Length)
            {
                totalSum += nums[end];
                // 寻找到右侧的窗口终止位置后,收缩左侧窗口
                while (totalSum >= target)
                {
                    ans = Math.Min(ans, end - start + 1);
                    totalSum -= nums[start];
                    start++;
                }
                end++;
            }
            return ans == int.MaxValue ? 0 : ans;
    }
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-05-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 209. 长度最小的子数组
    • 题目描述
      • 解法1:暴力解法:
        • 解法2:前缀和 + 二分查找
          • 解法3:滑动窗口解法:
            • C++实现
            • C#实现:
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档