leetcode(同向双指针 滑动窗口)209.长度最小的子数组 713.乘积小于K的子数组 3.无重复字符的最长子串
前言
学习灵茶山艾府的基础算法精讲03
209.长度最小的子数组
解题思路:
初始化left
和right
都是0
,都是从最左边开始的,然后求第一个子数组之和,小于K不符合要求,则right
向右移动,更新求和,如果这次求和大于等于K,符合要求,则让left
向右移动,更新求和,如果还符合要求,再次让left
向右移动
class Solution {
public:int minSubArrayLen(int target, vector<int>& nums) {int n = nums.size(), left = 0, ans = n + 1, sum = 0;for (int right = 0; right < n; right ++) {sum += nums[right];while (sum >= target) {ans = min(ans, right - left + 1);sum -= nums[left];left++;}}return ans <= n ? ans : 0;}
};
还有一种写法
class Solution {
public:int minSubArrayLen(int target, vector<int>& nums) {int n = nums.size(), left = 0, ans = n + 1, sum = 0;for (int right = 0; right < n; right ++) {sum += nums[right];while (sum - nums[left] >= target) {sum -= nums[left];left ++;}if (sum >= target) {ans = min(ans, right - left + 1);}}return ans <= n ? ans : 0;}
};
这种写法就是先更新left
,然后再求ans
注1: 这里ans
初始化是n + 1
,因为题里要求的是最小,设置为最大,如果没又符合要求,ans > n
,就返回0
。
注2: 这里的长度是right - left + 1
,设定一个固定值,就知道为什么是这个了
注3: 这里的时间复杂度是O(n)
,空间复杂度是O(1)
。虽然写了个二重循环,但是内层循环中对left ++
的总执行次数不会超过n
次,所以总的时间复杂度为O(n)
713.乘积小于K的子数组
解题思路:
首先,这道题都是正整数,如果k <= 1
,这是不可能有答案的,直接返回0
。
然后初始化left = 0, right = 0, ans = 0, prod
(表示乘积)=0
。
依此循环滑动窗口,prod = nums[right]
,如果,prod > k
,不符合要求,则让left
向右移动,prod ÷ nums[left]
,直到符合为止
只要有复合的ans += right - left + 1
,这样就能覆盖所有符合要求的子数组
class Solution {
public:int numSubarrayProductLessThanK(vector<int>& nums, int k) {if (k <= 1) return 0;int n = nums.size(), left = 0, ans = 0, prod = 1;for (int right = 0; right < n; right ++) {prod *= nums[right];while (prod >= k) {prod /= nums[left];left ++;}ans += right - left + 1;}return ans;}
};
注: 时间复杂度O(n)
,空间复杂度O(1)
3.无重复字符的最长子串
解题思路:
这道题使用哈希表映射,如果右指针对应的字符遇到重复的,则左指针一致向右移动,直到不再存在重复的为止
class Solution {
public:int lengthOfLongestSubstring(string s) {int n = s.size(), left = 0, ans = 0;unordered_map<char,int> cnt;for (int right = 0; right < n; right ++) {char c = s[right];cnt[c] ++;while (cnt[c] > 1) {cnt[s[left]] --;left ++;}ans = max(ans, right - left + 1);}return ans;}
};