[算法练习]Day 8: 变长滑动窗口
2904. 最短且字典序最小的美丽子字符串
也是滑动窗口,要想好如何移动
class Solution {
public:string shortestBeautifulSubstring(string s, int k) {string ans;int left = 0;int cnt = 0;for(int right = 0;right < s.size();right++){cnt += (s[right] == '1');// 左指针移动while((cnt > k) || (s[left] == '0')){cnt -= (s[left] == '1');left++;}if(cnt == k){string temp(s.begin()+left,s.begin()+right+1);if(ans.size() == 0)ans = temp;else if(ans.size() == temp.size())ans = (ans > temp)?temp:ans;elseans = (ans.size() < temp.size())?ans:temp;}}return ans;}
};
2875. 无限数组的最短子数组
我刚开始的思路就是对左右边界取模进行滑动窗口,但是数组不可能一直滑动去寻找解;这里如果nums的总和sum比target大,那么扩展2倍数组是一定能够得到答案的。但如果sum小于target,那么滑动窗口中就会额外出现完整个nums数组。因此我在这里设置了参数k来减少循环的次数。
class Solution {
public:int minSizeSubarray(vector<int>& nums, int target) {int ans = -1;int len = nums.size();long long s = 0;for(auto a:nums){s += a;}int k = ((target / s) + 1) * 2 ;int sum = 0;int left = 0;for(int right = 0; right < len * k ;right++){sum += nums[right % len];while(sum > target){sum -= nums[left % len];left++;}if(sum == target){if(ans == -1) ans = right-left+1;else ans = min(ans,right-left+1);}}return ans;}
};
但还是不行,最后会有一个案例超时。看了灵神的解析才想到,既然sum都已经比target大了,那为什么不直接减去!!!这样就不需要白白循环了!真是学到了
class Solution {
public:int minSizeSubarray(vector<int>& nums, int target) {int ans = -1;int len = nums.size();long long s = 0;for(auto a:nums){s += a;}int k = target / s ;target -= k*s;int sum = 0;int left = 0;for(int right = 0; right < len * 2 ;right++){sum += nums[right % len];while(sum > target){sum -= nums[left % len];left++;}if(sum == target){if(ans == -1) ans = right-left+1+k*len;else ans = min(ans,right-left+1+k*len);}}return ans;}
};
713. 乘积小于 K 的子数组
对于每一个right来说,都有right-left+1个对应的解
class Solution {
public:int numSubarrayProductLessThanK(vector<int>& nums, int k) {int ans = 0;int muti = 1;int left = 0;for(int right = 0;right < nums.size();right++){muti *= nums[right];while(muti >= k && left <= right){muti = muti / nums[left];left++;}ans += right - left + 1;}return ans;}
};
3258. 统计满足 K 约束的子字符串数量 I
相同的思路
class Solution {
public:int countKConstraintSubstrings(string s, int k) {int ans = 0;int cnt0 = 0;int cnt1 = 0;int left = 0;for(int right = 0;right < s.size();right++){if(s[right] == '1') cnt1++;else cnt0++;while(cnt1 > k && cnt0 > k){if(s[left] == '1') cnt1--;else cnt0--;left++;}ans += (right - left + 1);}return ans;}
};
1358. 包含所有三种字符的子字符串数目
注意符合要求的区间
class Solution {
public:int numberOfSubstrings(string s) {int ans = 0;int left = 0;vector<int>cnt(3,0);for(int right = 0;right < s.size();right++){char c = s[right];if(c == 'a') cnt[0]++;else if(c == 'b') cnt[1]++;else cnt[2]++;while((cnt[0] > 0) && (cnt[1] > 0) && (cnt[2] > 0)){ans += s.size() - right; char c1 = s[left];if(c1 == 'a') cnt[0]--;else if(c1 == 'b') cnt[1]--;else cnt[2]--;left++;}}return ans;}
};
2962. 统计最大元素出现至少 K 次的子数组
和上一个题的思路是一样的
class Solution {
public:long long countSubarrays(vector<int>& nums, int k) {int max = 0;for(auto i: nums){max = (i > max)?i:max;}long long ans = 0;int left = 0;int cnt = 0;for(int right = 0;right < nums.size();right++){cnt += (nums[right] == max);while(cnt >= k){ans += nums.size() - right;cnt -=(nums[left] == max);left++;}}return ans;}
};