暴力枚举
使用两个for循环,分别表示两个边界——左边界和右边界;时间复杂度为O()
// @lc code=start
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int left;
int right;
int ans=Integer.MAX_VALUE;
for(left=0; left<nums.length; left++){
int sum=0;
for(right=left; right<nums.length; right++){
sum+=nums[right];
if(sum>=target){
ans=Math.min(ans, right-left+1);
break;
}
}
}
return ans==Integer.MAX_VALUE ? 0:ans;
}
}
// @lc code=end
前缀和+二分搜索
前缀和:新建的一个数组,sum[i]表示前i个元素的和
要找的满足条件sum[i]-sum[j]>=target,即sum[i]>=sum[j]+target
使用两个for,对于每个sum[i]进行二分搜索其后面的j,所以复杂度为O()
能够使用二分搜素的原因:数组均为非负,所以前缀和为递增数列,可以使用二分搜索。
基础知识补充
1.在给答案变量赋初值时,可以用Integer.MAX_VALUE
2.二分搜索在java里可以使用现有库函数:Arrays.binarySearch(数组名, 目标值);——见笔记
3.Math.min(a, b); 比较a,b两个元素哪个更小,多学一个函数
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int sum[]=new int[nums.length+1];
sum[0]=0;
int ans=Integer.MAX_VALUE;
//为前缀和数组赋值
for(int i=1; i<sum.length; i++){
sum[i]=sum[i-1]+nums[i-1];
}
//对每个i进行二分查找
for(int i=1; i<sum.length; i++){//个人总把sum和num长度作为边界条件时搞混
int temp=target+sum[i-1];//确定每个i所需的bound——难点
int bound=Arrays.binarySearch(sum, temp);
if(bound<0)bound=-bound-1;//对Arrays.binarySearch的掌握程度
if(bound<=nums.length)ans=Math.min(ans, bound-i+1);
}
return ans==Integer.MAX_VALUE ? 0:ans;
}
}
滑动窗口
官方题解说的很好了,直接上码:
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int ans=Integer.MAX_VALUE;
int start=0;int end=0;int sum=0;
while(end<nums.length){
sum+=nums[end];
while(sum>=target){
ans=Math.min(ans, end-start+1);
sum-=nums[start++];
}
end++;//放哪里?????——其始终指向sum序列中的首元素和末尾元素
}
return ans==Integer.MAX_VALUE ? 0:ans;
}
}
1.其实,方法二前缀和和方法三滑动窗口都有一个共同的特点:在得到一个新答案时,和旧答案相比是否比旧答案更优,更优则替换。 初始答案赋值都是将其赋值为Integer.MAX_VALUE或Integer.MIN_VALUE。借鉴
2.最终结果return都是使用?运算符,如果结果为结果变量初始赋值,那么返回0(不要遗漏)