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

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;
    }
};

猜你喜欢

转载自blog.csdn.net/m0_55704585/article/details/129427439