Leetcode每日一题2/6~2/10总结

还是关于滑动窗口的问题,变化在于边界的判定变得困难了,什么时候改变left,什么时候right++,需要充分的考虑。题目就出现了截止条件为right == len - 2的情况,同时最后一个窗口需要单独判断。

2/6

1423-可获得的最大点数

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

992-k个不同整数的子数组

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)

猜你喜欢

转载自blog.csdn.net/qq_42883222/article/details/113783264