LeetCode练习跳转:. - 力扣(LeetCode)
1.暴力求解:
此种解法就是按照正常的思维,从某一个元素向后一个一个累加,等满足条件后就记下来这个子数组的长度,然后起始点向后移一位重复同样的操作,最终选择最短的那个子数组即可,很明显,求解需要三个记录变量,分别用来记录最终的结果子数组长度、记录当前这个子数组的总和、记录当前这个子数组的长度;需要两层循环,一层用来把控起始元素点,从头到尾,一层用来向后做累加运算。其中需注意的点就是更换起始元素点时子数组的和及长度的记录变量要置0。代码如下:
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums)
{
int result = INT32_MAX; //最终的结果保存在result中
for(int i = 0;i<nums.size();i++)//i是起始点
{
int subarrlen = 0;//子数组的长度,每次起始点变更时都要重新置0
int sum = 0;
for(int j = i;j<nums.size();j++)//j是向后移动的搜索点,在未达到目标前每次向后移动一个位置
{
sum += nums[j];
subarrlen++;
if(sum>=target)
{
result = result > subarrlen ? subarrlen : result;//result每次都选择更小的子数组长度进行更新
break;//只要这次的起点i开始的子数组达到target目标。就直接结束j继续向后,开始下一个起点i的搜索
}
}
}
return result == INT32_MAX ? 0 : result;//如果未能找到符合条件的子数组,返回0。
}
};
很明显,两层循环的时间复杂度为O(n^2),leetcode中的测试样例测试超时,无法通过:
暴力求解的方法可行,但是时间复杂度过高,下面介绍比较diao的方法,滑动窗口法:
2.<滑动窗口法>求解:
滑动窗口,顾名思义,子数组就像一个窗口一样滑动,这个子数组的长度并不是随着每次起始节点变化后从零再次开始计算的,而是在找到符合条件的子数组之后,起始节点后移,看此时的子数组是否还符合条件,若符合,则起始节点再次后移,若不符合,则末元素后移,以此类推,直到末节点扫描到数组末尾。值得注意的是,虽然代码中for循环里嵌套了一个while循环,但是while循环的时间复杂的是一个常数阶,也可以按照Carl佬的说法,每个元素都是在进来子数组和出去子数组时被操作,每个数组都被操作两次,则总时间复杂度为O(2n),相比暴力求解提升不少,leetcode可以测试通过。代码如下:
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums)
{
int result = INT32_MAX; //最终的结果保存在result中
int i = 0;//表示当前子数组的初始位置
int subarrlen = 0;//子数组的长度,每次起始点变更时都要重新置0
int sum = 0;
for(int j = i;j<nums.size();j++)//j是向后移动的搜索点,在未达到目标前每次向后移动一个位置
{
sum += nums[j];
subarrlen++;
while(sum>=target)//这边不用if,因为如果起始元素点后移一位后子数组的和仍符合要求,则需要继续进行一次起始元素后移操作
{
result = result > subarrlen ? subarrlen : result;//result每次都选择更小的子数组长度进行更新
sum -= nums[i];//****滑动窗口的精髓,子数组符合条件之后,起始点直接后滑一位,同时子数组的和、长度做出更新
i++;
subarrlen--;
}
}
return result == INT32_MAX ? 0 : result;//如果未能找到符合条件的子数组,返回0。
}
};