力扣(LeetCode)209. 长度最小的子数组(C语言)

一、环境说明

  1. 本文是 LeetCode 209题 : 长度最小的子数组,使用c语言实现
  2. 一题双解
  3. 测试环境:Visual Studio 2019

二、代码展示

2.1 前缀和+二分查找

//前缀和+二分查找
int binarySearch(int left,int right,int target,int nums[]){
    if(nums[right]<target){//说明最大前缀和小于target
        return -1;
    }
    int mid = 0;
    while(left<=right){
        mid=left+((right-left)>>1);
        if(nums[mid]>=target){//大于目标值
            right = mid -1;
        }else{//小于等于目标值
            left = mid +1;
        }
    }
    return left;
}
int minSubArrayLen(int target, int* nums, int numsSize) {//求长度最小的子数组
    int* sums = (int*)calloc(numsSize + 1, sizeof(int));//前缀和数组
    for (int i = 1; i <= numsSize; i++) {//第0个前缀和为0,第1个前缀和为0+nums[0],以此类推,
        //第n个前缀和为sums[n-1] + nums[n-1],意为前n-2个数+第n-1个数。
        sums[i] = sums[i - 1] + nums[i - 1];
    }
    int ans = INT_MAX;//
    for (int i = 1; i <= numsSize; i++) {
        int search_target = target + sums[i - 1];//搜索的位置,是前缀和大于对应的位置
        int len = binarySearch(1, numsSize, search_target, sums);//第一个小于target+sums[i]的位置,
        //就是从i开始,前缀和>=target的一个长度
        if (len != -1) {
            ans = ans < len - i + 1 ? ans : len - i + 1;//答案是最小长度
        }
    }
    return ans == INT_MAX ? 0 : ans;//ans==INT_MAX,说明ans没有进入循环,整个数组前缀和都小于target
}

2.2 滑动窗口

//滑动窗口
int minSubArrayLen(int target, int* nums, int numsSize){//求长度最小的子数组
    int left = 0,right = 0;
    int sum =0,ans = INT_MAX;
    while(right<numsSize){//遍历nums
        sum+=nums[right];//sum每次加上当前nums[right]数字
        while(sum>=target){//left右移
            ans = ans<right -left +1?ans:right - left +1;
            sum-=nums[left++];//sum减去nums[left]对应数字,left右移
        }
        right++;//right右移
    }
    return ans==INT_MAX?0:ans;
}

三、思路分析

  • 这是作者第一次接触前缀和。虽然官方答案最优解给的是滑动窗口,但是这题的前缀和+二分查找也很简单。适合新手入坑前缀和。
  • 滑动窗口很简单,不讲了。
  • 讲讲前缀和。
  1. 这种计算区间内数字之和的题目,区间内全是正数。用前缀和,生成递增数组,然后就可以二分查找啦。
  2. 生成前缀和数组,有个技巧,初始化第0个前缀和sums[0]=0。遍历从i=1开始,第1个前缀和sums[1]=0+nums[0],第n个前缀和sums[n]=sums[n-1]+nums[n-1],第n个前缀和=前n-2个数+第n-1个数。
  3. 二分查找是个手感问题,比如我这里循环体内,设置nums[mid]>=target,它的搜索结果left,就是第一个大于target的数字位置。想要提升能力的读者,可以做二分专项~

四、代码分析

  • 看注释 ^ _ ^

五、AC

滑动窗口
前缀和+二分查找

六、复杂度分析

滑动窗口复杂度

  1. 时间复杂度:O(n) ,n是nums数组的大小,遍历nums的时间复杂度为O(n)。
  2. 空间复杂度:O(1),除若干变量使用的常量空间,没有使用额外的线性空间。

前缀和+二分查找复杂度

  1. 时间复杂度:O(nlogn) ,n是nums数组的大小,遍历nums并且二分查找target的时间复杂度是O(nlogn)。
  2. 空间复杂度:O(n),额外申请了sums数组,n是sums数组的大小,用于保存每个位置的前缀和,空间复杂度O(n)
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

清墨韵染

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值