【LeetCode面试150】——209长度最小的子数组

博客昵称:沈小农学编程

作者简介:一名在读硕士,定期更新相关算法面试题,欢迎关注小弟!

PS:哈喽!各位CSDN的uu们,我是你的小弟沈小农,希望我的文章能帮助到你。欢迎大家在评论区唠嗑指正,觉得好的话别忘了一键三连哦!😘

题目难度:中等

默认优化目标:最小化时间复杂度。

Python默认为Python3。

目录

1 题目描述

2 题目解析

3 算法原理及代码实现

3.1 暴力求解

3.2 前缀和+二分查找

3.3 滑动窗口

参考文献


1 题目描述

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

找出该数组中满足其总和大于等于 target 的长度最小的 子数组[numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度如果不存在符合条件的子数组,返回 0

示例 1:

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

示例 2:

输入:target = 4, nums = [1,4,4]
输出:1

示例 3:

输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0

提示:

  • 1 <= target <= 109

  • 1 <= nums.length <= 105

  • 1 <= nums[i] <= 105

进阶:

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

2 题目解析

输入是一个正整数数组nums和一个正整数target,输出是最短子数组长度。约束条件是子数组中的所有元素之和等于target

 

3 算法原理及代码实现

3.1 暴力求解

枚举每个下标作为子数组的开始,对于每个开始下标i,需要找到大于或等于i的最小下标j,使得nums[i]到nums[j]的元素大于或等于target,并更新子数组的长度。

时间复杂度O(n^2),空间复杂度O(1)。

C++代码实现

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int n=nums.size();
        int sublen=10000;
        if(!n) return 0;
        else{
            for(int i=0;i<n;i++){
                int sum=0;
                for(int j=i;j<n;j++){
                    sum+=nums[j];
                    if(sum>=target){
                        sublen=min(sublen,j-i+1);
                        break;
                    }
                }
            }
        }
        return sublen==10000 ? 0 : sublen;
    }
};

Python代码实现

class Solution:
    def minSubArrayLen(self, target: int, nums: List[int]) -> int:
        n,sublen=len(nums),10000
        if(not n):
            return 0
        else:
            for i in range(n):
                sum=0
                for j in range(i,n):
                    sum+=nums[j]
                    if(sum>=target):
                        sublen=min(sublen,j-i+1)
                        break
        return 0 if sublen==10000 else sublen

3.2 前缀和+二分查找

如果使用二分查找,可以将时间复杂度优化到O(log n)。为了使用二分查找,我们需要一个数组sums来记录nums的前缀和。因为nums中每个元素都是正的,所以前缀和递增。

 

时间复杂度O(n log n),空间复杂度O(n)。

C++代码实现

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int n=nums.size();
        int sublen=1000000;
        if(!n) return 0;
        vector<int> sums(n+1,0);
        for(int i=1;i<n+1;i++)
            sums[i]=sums[i-1]+nums[i-1];
        for(int i=1;i<n+1;i++){
            int target_new=target+sums[i-1];
            auto bound=lower_bound(sums.begin(),sums.end(),target_new);
            if(bound!=sums.end()) 
                sublen=min(sublen,static_cast<int>((bound-sums.begin()-(i-1))));
        }
        return sublen==1000000 ? 0 : sublen;
    }
};

Python代码实现

class Solution:
    def minSubArrayLen(self, target: int, nums: List[int]) -> int:
        n,sublen=len(nums),1000000
        if(not n): 
            return 0;
        sums=[0]
        for i in range(n):
            sums.append(sums[-1]+nums[i])
        for i in range(1,n+1):
            target_new=target+sums[i-1]
            bound=bisect.bisect_left(sums,target_new)
            if bound!=len(sums):
                sublen=min(sublen,bound-i+1)
        return 0 if sublen==1000000 else sublen 

3.3 滑动窗口

定义两个指针left和right表示滑动窗口的开始和结束位置,sum用于计算子数组中的元素和。

left和right初始都指向下标0。每一轮迭代,sum+=nums[end],如果sum大于等于target,更新sublen,然后sum减去sum[left],left右移。right右移。以此类推。

 

时间复杂度O(n),空间复杂度O(1)。

C++代码实现

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int n=nums.size();
        int left=0,right=0;
        int sublen=1000000;
        int sum=0;
        if(!n) return 0;
        while(right<n){
            sum+=nums[right];
            while(sum>=target){
                sublen=min(sublen,right-left+1);
                sum-=nums[left];
                left++;
            }
            right++;
        }
        return sublen==1000000 ? 0 : sublen;
    }
};

Python代码实现

class Solution:
    def minSubArrayLen(self, target: int, nums: List[int]) -> int:
        n,sublen=len(nums),1000000
        left,right,sum=0,0,0
        if(not n): 
            return 0
        while right<n:
            sum+=nums[right]
            while sum>=target:
                sublen=min(sublen,right-left+1)
                sum-=nums[left]
                left+=1
            right+=1
        return 0 if sublen==1000000 else sublen

参考文献

力扣面试经典150题

力扣官方题解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值