Leetcode209. 长度最小的子数组

题目跳转链接

有暴力解法和窗口滑动法,暴力解法是否值得掌握

 暴力解法显然是一种简单而直观的解法,其时间复杂度为 O(N^2),空间复杂度为 O(1)。如果输入规模不大,暴力解法可能也可以接受。

但在面对规模较大,或对性能要求较高的场景下,暴力解法就会因其高时间复杂度而表现较差。此时就需要使用其他算法,如滑动窗口法,它的时间复杂度为 O(N),空间复杂度也为 O(1)。

因此,虽然暴力解法简单直观,但在开发实际项目中,我们通常需要考虑代码的效率和性能,所以掌握其他算法,如滑动窗口法等也是非常必要和有益的。但是,了解和掌握暴力解法也非常重要,因为在某些情况下它可能很有用,而且它也是其他算法的基础。

暴力解法

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums)
     {
        int result = INT32_MAX; // 最终的结果
        int sum = 0; // 子序列的数值之和
        int subLength = 0; // 子序列的长度
        for (int i = 0; i < nums.size(); i++) 
          { // 设置子序列起点为i
            sum = 0;
            for (int j = i; j < nums.size(); j++) 
              { // 设置子序列终止位置为j
                sum += nums[j];
                if (sum >= s) 
                { // 一旦发现子序列和超过了s,更新result
                    subLength = j - i + 1; // 取子序列的长度
                    result = result < subLength ? result : subLength;
                    break; // 因为我们是找符合条件最短的子序列,所以一旦符合条件就break
                }
            }
        }
        // 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
        return result == INT32_MAX ? 0 : result;
    }
};


滑动窗口解法

代码随想录 209.长度最小的子数组

滑动窗口是一种基于双指针的算法,它可以用于解决一些数组/字符串的子元素问题,例如:找到最长的子数组、最小的子串等等。

滑动窗口算法的思路就是维护两个指针,一个左指针和一个右指针,它们之间的区间就是滑动窗口。我们需要根据题目要求不断调整这两个指针的位置,来达到求解问题的目的。

在本题中,我们需要找到数组中满足其和 ≥ target 的长度最小的连续子数组,那么我们就可以使用滑动窗口算法来解决这个问题。
滑动窗口法的思路:

  • 定义窗口的左右边界left,right初值为0
  • 当窗口内的数字之和小于给定值时,调整右边界right,使窗口扩大
  • 当窗口内的数字之和大于等于给定值时,记录窗口大小,并将左边界left向右移动一格,

具体步骤如下:

  1. 初始化左指针 i 和右指针 j,它们初始值都为 0。
  2. 初始化滑动窗口的数值之和 sum,初始值为 0。
  3. 当 sum < target 时,右指针向右移动一位,将 nums[j] 加入到 sum 中。
  4. 当 sum >= target 时,记录当前子数组的长度 (j - i + 1),并更新最小值。
  5. 然后移动左指针 i,将 nums[i] 从 sum 中减去,继续判断 sum 是否大于等于 target。
  6. 重复步骤 3-5,直到 j 超过数组范围。

这个算法的核心就是维护一个滑动窗口,不断调整左右指针的位置,来达到求解问题的目的。我们可以把这个过程想象成在一个数组上滑动一个大小可变的窗口,每次根据窗口内的值来判断左右指针的移动方式。

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) 
    {
        int result=INT32_MAX;
        int sum=0;
        int i=0;
        int subLength=0;  //滑动窗口的长度

        for(int j=0;j<nums.size();j++)
        {
            sum+=nums[j];
            while(sum>=target)
            {
                subLength=(j-i+1);  //取子序列的长度
                result=result<subLength?result:subLength;
//跟踪这个子数组的长度。 只有在找到更短的子数组时,才会更新此长度。它将最小长度分配给result变量。
                sum-=nums[i++];
//5. 然后移动左指针 i,将 nums[i] 从 sum 中减去,继续判断 sum 是否大于等于 target。
//6. 重复步骤 3-5,直到 j 超过数组范围。
            }
        }
        // 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
        return result == INT32_MAX ? 0 : result;

    }
};


相同的
class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums)
     {
         int n=nums.size();
      int left=0;
      int right=0;
      int sum=0;
        int result=INT_MAX;
      while(right<n)
      {
         sum+=nums[right];
             while(sum>=target)
             {
                 result=result<right-left+1?result:right-left+1;
                 
                 sum-=nums[left];
                 left++;
             }

        
      right++;

      }

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

posted @ 2023-03-21 23:00  专心Coding的程侠  阅读(42)  评论(0)    收藏  举报