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