力扣1004. 最大连续1的个数 III

发布时间 2023-07-12 14:51:04作者: Yohoc

题目:

给你字符串 s 和整数 k 。

请返回字符串 s 中长度为 k 的单个子字符串中可能包含的最大元音字母数。

英文中的 元音字母 为(a, e, i, o, u)。

 

示例 1:

输入:s = "abciiidef", k = 3
输出:3
解释:子字符串 "iii" 包含 3 个元音字母。
示例 2:

输入:s = "aeiou", k = 2
输出:2
解释:任意长度为 2 的子字符串都包含 2 个元音字母。
示例 3:

输入:s = "leetcode", k = 3
输出:2
解释:"lee"、"eet" 和 "ode" 都包含 2 个元音字母。
示例 4:

输入:s = "rhythms", k = 4
输出:0
解释:字符串 s 中不含任何元音字母。
示例 5:

输入:s = "tryhard", k = 4
输出:1
 

提示:

1 <= s.length <= 10^5
s 由小写英文字母组成
1 <= k <= s.length

 

思路:

zn[i]表示数组下标从0~i中0的个数 

对于数组nums的区间[left, right]而言,只要它包含不超过k个0,我们就可以根据它构造出一段满足要求,且长度为right-left+1的区间。

即:zn[right] - zn[left - 1] <= k 

方法一:二分查找 (zn是一个递增数列)

zn[right] - zn[left - 1] <= k 等价于 zn[left - 1] >= zn[right] - k;

枚举right,对于每一个right寻找第一个大于等于zn[right] - k 的left - 1

 

方法二:滑动窗口

由于zn[right] - k 单调递增,我们就可以使用滑动窗口来实时地维护 left和 right。在right 向右移动的过程中,我们同步移动 left,直到 left 为首个(即最小的)满足 

zn[left - 1] >= zn[right] - k 的位置,此时我们就可以使用此区间对答案进行更新了。

 

 

 

代码:(滑动窗口法)

class Solution {
public:
    int longestOnes(vector<int>& nums, int k) {
        int n = nums.size();
        int zn[999999] = {0};
        nums[0] == 0 ? zn[0] = 1 : zn[0] = 0; 
        for(int i = 1; i < n; i++){
            if(nums[i] == 0){
                zn[i] = zn[i - 1] + 1;
            }else{
                zn[i] = zn[i - 1];
            }
        }
        int l = 0, ans = 0;
        for(int r = 0; r < n; r++){
            int tmp;
            if(l - 1 < 0){
                tmp = zn[r];
            }else{
                tmp = zn[r] - zn[l - 1];
            }
            while(tmp > k){
                l++;
                if(l - 1 < 0){
                    tmp = zn[r];
                }else{
                    tmp = zn[r] - zn[l - 1];
                }
            }
            ans = max(ans, r - l + 1);
        }
        return ans;
    }
};