日常算法刷题——力扣209(双指针—滑动窗口、前缀和)

文章介绍了解决寻找数组中最小覆盖子数组长度以使和大于等于目标值的问题的三种方法:暴力求解(O(n^2))、前缀和结合二分查找(O(n*logn))以及滑动窗口双指针法(O(n))。每种方法都有其独特之处,暴力求解中包含精妙的三目运算,前缀和配合二分查找降低了复杂度,滑动窗口法通过双指针对满足条件的情况进行循环处理,优化了效率。
摘要由CSDN通过智能技术生成

2023/3/10 每日刷算法题第六天

本题是读起来很顺利,但是一开始理解错误,我还进行了排序倒着找数据。后来才发现错的离大普。一时间不知道从何下手,看了网上的教程学习了之后,发现此题共有三种解法。

解法一 暴力求解:
暴力求解的思路就是从第一个数字依次往后找,时间复杂度明显是O(n^2),跑测试用例能过,但是提交之后会超时。
但暴力求解中,在参考其他人代码中发现了很精妙的三目运算,具体见代码如下:
代码:

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
       // 暴力求解   
       int result=INT32_MAX;  
       int length=0;
       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)
               {
                   length=j-i+1;
                    result=result<length?result:length;
                   break;
               }
           }
       }
       result=result==INT32_MAX?0:result;
       return result;
    }
};

解法二:前缀和操作
前缀和就是单独定义一个数组,新定义的数组的第i个位置存储的就是原数组从0到第i的前i项和,然后利用第j项 减去 第i项就是等于i到j的连续数据之和。
之后,更巧妙的是利用二分查找,通过做差,找到最小的间距长度length。此时的算法复杂度是O(n*log n),但是这种写法我个人感觉细节贼多,不好理解!

代码:

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
       // 前缀和 
       int sum=0;
       int re=0
        vector<int>arr;
        arr.push_back(0);
      for(int i=0;i<nums.size();i++)
      {
          sum+=nums[i];
          arr.push_back(sum);
      }

      //二分查找最小间距
      for(int i=0;i<nums.size();i++)
      {
          int left=i,right=nums.size()-1;
          while(left<=right)
          {
              int mid=left+(right-left)/2;
              if(arr[mid+1]-arr[i]<target)
                    left=mid+1;
                else
                {
                    right=mid-1;
                }
          }
          if(left!=nums.size())
          {
              int len=left-i+1;
                re=re==0?len:min(re,len);
          }
      }
      return re;
    }
};

解法三:双指针——滑动窗口

滑动窗口的本质也就是双指针操作,而双指针操作写了几个题之后我发现本质就是想想如何将两个for循环修改为一个for循环完成,时间复杂度就大大降低为O(n)。
此题的滑动窗口就只需要按照双指针的想法,right指针先跑,当满足条件的时候,就把letf指针向左移动,以求满足length最小。但是这里需要注意一个细节,**当满足条件的时候,我们经常就是用if进行判断,但是我们应该一种情况就是 1 1 1 3 (3),这种情况length最小值为1,所以要达到目的,这里应该使用循环进行缩小,**我就卡在这里很久,感觉没错,但是总不对。
代码:

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        //滑动窗口
        int sum=0,length=INT32_MAX;
        int left=0,right=0;

        for(;right<nums.size();right++)
        {
            sum=sum+nums[right];
            while(sum>=target)      //这里要是循环
            {
                int len=(right-left+1);
                length=length<len?length:len;
                sum-=nums[left];
                left++;
            }
        }
        return length==INT32_MAX?0:length;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值