1. 209 长度最小的子数组
1.1 题目描述
给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其总和大于等于 target 的长度最小的 子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
示例 1:
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
示例 2:
输入:target = 4, nums = [1,4,4]
输出:1
示例 3:
输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0
提示:
1 <= target <= 1091 <= nums.length <= 1051 <= nums[i] <= 104
1.2 思路
1.2.1 暴力法
我们设置循环变量为i,在遍历nums的过程中,不断向右扩展得到的子数组,判断该子数组之和是否满足>=target。如果满足再判断它的长度是否比当前得到的最小长度要小,如果是,则将该子数组长度保存,具体实现看1.3
1.2.2 同向双指针+滑动窗口
核心:由于该题目数组元素都是正数且寻找的是子数组(连续),在遍历过程中,不用一个一个进行扩展,而是用上次遍历扩展得到的结果再包括当前元素,因为上次得到的子数组元素和>=target,再加上一个正数肯定也满足>=target
设置双指针left和right,初始值都为0,即表示nums的第一个元素下标。
将right作为循环变量进行遍历nums数组,在遍历过程中,保存当前left到right对应的子数组元素之和为s,并判断s是否大于等于target。
如果s>=target表示当前子数组是满足条件的子数组,如果当前子数组长度小于我们之前得到的子数组长度的最小值,保存该长度。
此时可以不断缩小数组的左端点,即left++,如果left到right对应的子数组仍然满足条件,判断它长度如果比之前小,就保存他的长度,直到不满足条件为止。
不满足条件之后回到主循环,right++,如此往复
以示例1举例子
1.初始状态如下:

2. right作为循环变量不断遍历nums,直到满足left到right对应的子数组之和满足>=target
此时left=0 right为3

3. 由于已经满足了条件,不断缩小左端点,left++,直到不满足条件为止。在left++过程中得到满足条件的子数组,不断更改当前的res

4. 不幸left++一次就不满足条件了,所以res没变,此时回到主循环,将right++到满足条件为止

5. 再次将左端点缩小 left++,到不满足条件为止,此时res=3 也就是对应的[1,2,4]子数组

6. 回到主循环,right++

7.不断缩小左端点,left++,此时res=2,对应的子数组就是[4,3]

8.退出循环 返回res
1.3 代码(C++版本)
1.3.1 暴力法
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int res = nums.size()+1;
for(int i = 0; i < nums.size(); i++) {
int s = 0;
for(int j = i; j < nums.size(); j++) {
s += nums[j];
if(s >= target) {
res = min(j-i+1, res);
}
}
}
return res >= nums.size()+1 ? 0 : res;
}
}
1.3.2 双指针+滑动窗口
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int res = nums.size()+1;
int left = 0;
int s = 0;
for(int right = 0; right < nums.size(); right++) {
s += nums[right];
while(s >= target) {
res = min(res, right-left+1);
s -= nums[left];
left++;
}
}
return res >= nums.size()+1 ? 0 : res;
}
};
1.4 时间复杂度和空间复杂度
时间复杂度:O(N)
空间复杂度:O(1)
2. 713 乘积小于等于K的子数组
2.1 题目描述
给你一个整数数组 nums 和一个整数 k ,请你返回子数组内所有元素的乘积严格小于 k 的连续子数组的数目。
示例 1:
输入:nums = [10,5,2,6], k = 100
输出:8
解释:8 个乘积小于 100 的子数组分别为:[10]、[5]、[2]、[6]、[10,5]、[5,2]、[2,6]、[5,2,6]。
需要注意的是 [10,5,2] 并不是乘积小于 100 的子数组。
示例 2:
输入:nums = [1,2,3], k = 0
输出:0
提示:
1 <= nums.length <= 3 * 1041 <= nums[i] <= 10000 <= k <= 106
2.2 思路
参考上面长度最小的子数组,这题也是设置同向双指针,其中一个作为循环变量,主动移动,另一个根据是否满足条件调整移动。注意在移动过程中,使用一个变量记录当前子数组的乘积,使用一个变量记录结果,出现一个满足条件的子数组就使结果+1。
k<=1时单独考虑
2.3 代码(C++)
class Solution {
public:
int numSubarrayProductLessThanK(vector<int>& nums, int k) {
if(k <= 1) {
return 0;
}
int res = 0;
int left = 0;
int prod = 1;
for(int right = 0; right < nums.size(); right++) {
prod *= nums[right];
while(prod >= k && nums[left] > 0) {
prod /= nums[left];
left++;
}
res += right - left + 1;
}
return res;
}
};
2.4 时间复杂度和空间复杂度
时间复杂度:O(N)
空间复杂度:O(1)
3. 3 无重复字符的最长子串
3.1 题目描述
给定一个字符串 s ,请你找出其中不含有重复字符的 最长 子串 的长度。
示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
提示:
0 <= s.length <= 5 * 104s由英文字母、数字、符号和空格组成
3.2 思路
思路与上两题类似,只是设置了一个map用于保存每个字符出现的个数
如果当前right对应的字符有重复,则left++
3.3 代码(C++)
class Solution {
public:
int lengthOfLongestSubstring(string s) {
unordered_map<char, int> count;
int res = 0;
int left = 0;
for(int right = 0; right < s.size(); right++) {
count[s[right]]++;
while(count[s[right]] > 1) {
//就是当前right的元素出现了两次 有重复
//移除左边元素
count[s[left]]--;
left++;
}
res = max(res, right-left+1);
}
return res;
}
};
3.4 时间复杂度和空间复杂度
时间复杂度:O(N)
空间复杂度:O(1)/O(128)/O(len(set(s)))
——同向双指针 滑动窗口&spm=1001.2101.3001.5002&articleId=148246394&d=1&t=3&u=b7b56ce3efbd474786fc495730d05cfa)
3547

被折叠的 条评论
为什么被折叠?



