还是关于滑动窗口的问题,变化在于边界的判定变得困难了,什么时候改变left,什么时候right++,需要充分的考虑。题目就出现了截止条件为right == len - 2的情况,同时最后一个窗口需要单独判断。
2/6
2/7
题目描述
思路 逐步判断法
注释已经说得很清楚了
class Solution {
public:
bool checkPossibility(vector<int>& nums) {
int len = nums.size();
if(len < 3) return false;
int count = 0;
for(int i = 1; i < len; i++) {
//出现非递增元素nums[i - 1]
if(nums[i-1] > nums[i]) {
count++;
if(count > 1) return false;
//如果i-2不存在,那么nums[i-1]就是开头,只能自己变小
//如果i-2存在,且发现为 3 5 1这种情况
//我们最小程度改变nums[i] = nums[i - 1]
if(i - 2 >= 0 && nums[i - 2] > nums[i]) {
nums[i] = nums[i - 1];
} else {
//如果i-2存在,且发现为 1 5 3 / 1 5 1 这种情况
//我们改变nums[i - 1] = nums[i]/nums[i - 2]都可以
//但是nums[i-2]不一定存在
nums[i - 1] = nums[i]
}
}
}
}
};
2/8
题目描述
思路 滑动数组
将窗口分为长度为1和长度大于1两种情况分析。
- 长度为1时,left和right同时前进,直到找到一个
arr[left] != arr[left + 1]
的情况为止
if (left == right) {
if (arr[left] == arr[left + 1]) {
left++;
}
right++;
}
可见停止的时候,right = left + 1
- 长度大于1时,两种情况
- 1.构成湍流数组 —> right++
- 2.不构成 ----> left = right
最后每一步都更新当前解
终止条件:right = len - 2
因为每一步判断,right都与right + 1进行过比较,符合的话right就变成right + 1,所以到len - 2为止就比较完成了。
class Solution {
public:
int maxTurbulenceSize(vector<int>& arr) {
int n = arr.size();
int ret = 1;
int left = 0, right = 0;
while (right < n - 1) {
if (left == right) {
if (arr[left] == arr[left + 1]) {
left++;
}
right++;
} else {
if (arr[right - 1] < arr[right] && arr[right] > arr[right + 1]) {
right++;
} else if (arr[right - 1] > arr[right] && arr[right] < arr[right + 1]) {
right++;
} else {
left = right;
}
}
ret = max(ret, right - left + 1);
}
return ret;
}
};
注意事项
很多题目都是到right = len - 1为止,因为判断的是当前的right是不是符合条件。而这题判断的是right + 1,所以要小心,不要想当然。
2/9
2/10
题目描述
思路 哈希表 + 滑动窗口
固定滑动窗口的大小,一直往右移动,判断哈希表是否和s1的哈希表相同,
同时注意s1 > s2的情况可能产生越界,需要特判
class Solution {
public:
bool checkInclusion(string s1, string s2) {
if(s1.size() > s2.size()) return false;
vector<int> m1(26,0);
vector<int> m2(26,0);
int len = s1.size();
int len2 = s2.size();
int left = 0, right = len;
for(char c: s1) {
m1[c - 'a']++;
}
//先扩大窗口
for(int i = 0; i < len; i++) {
m2[s2[i] - 'a']++;
}
while(right < len2) {
if(m2 == m1) return true;
m2[s2[right] - 'a']++;
m2[s2[left]- 'a']--;
left++;
right++;
}
return m1 == m2;
}
};
进入while循环的时候,right初始值是len,然后进行第一次的判断之后right就变成len + 1,left变为1,
这看起来很绕,因为left和right之间的窗口长度并不是len,而是len+1,然后最后当right = len2的时候,处于判断最后一个窗口的阶段,也就是while循环是延后判断的,先+1,下一个循环再进行判断,所以我们return 前还要进行判断。
可能就有小伙伴觉得这样太奇怪了。
所以对代码行了一定的修改:
class Solution {
public:
bool checkInclusion(string s1, string s2) {
if(s1.size() > s2.size()) return false;
vector<int> m1(26,0);
vector<int> m2(26,0);
int len = s1.size();
int len2 = s2.size();
int left = 0, right = len - 1;
for(char c: s1) {
m1[c - 'a']++;
}
//先扩大窗口
for(int i = 0; i < len; i++) {
m2[s2[i] - 'a']++;
}
while(right < len2 - 1) {
if(m2 == m1) return true;
m2[s2[left]- 'a']--;
left++;
right++;
m2[s2[right] - 'a']++;
}
return m1 == m2;
}
};
这样right和left之间就有len个元素了,但是要特别注意,right需要小于len2 - 1,因为最后一次right++会越界
同样的,最后一个窗口也需要单独判断
或者还可以这样写:
class Solution {
public:
bool checkInclusion(string s1, string s2) {
vector<int> m1(26,0);
vector<int> m2(26,0);
for(char c: s1) {
m1[c - 'a']++;
}
int right = 0, left = 0;
int len = s1.size();
int len2 = s2.size();
while(right < len2) {
if(right - left + 1 > len) {
m2[s2[left]- 'a']--;
left++;
}
m2[s2[right] - 'a']++;
right++;
if(m2 == m1) return true;
}
return false;
}
};
反正哪个好理解就用哪个,但结果来看第二种是最快的
时间复杂度O(n)
空间复杂度O(n)