滑动窗口(十五)2962. 统计最大元素出现至少 K 次的子数组(越长越合法型)

2962. 统计最大元素出现至少 K 次的子数组

给你一个整数数组 nums 和一个 正整数 k 。

请你统计有多少满足 「 nums 中的 最大 元素」至少出现 k 次的子数组,并返回满足这一条件的子数组的数目。

子数组是数组中的一个连续元素序列。

示例 1:

复制代码
输入:nums = [1,3,2,3,3], k = 2
输出:6
解释:包含元素 3 至少 2 次的子数组为:[1,3,2,3]、[1,3,2,3,3]、[3,2,3]、[3,2,3,3]、[2,3,3] 和 [3,3] 。

示例 2:

复制代码
输入:nums = [1,4,2,1], k = 3
输出:0
解释:没有子数组包含元素 4 至少 3 次。

提示:

  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= 106
  • 1 <= k <= 105

首先使用N^2的方法,固定左端点,枚举所有的子数组,然后看他们中最大值出现的次数如果大于k就++

优化:发现当cnt为k的时候,后续就不需要处理了,直接把j后面所有的值用n-j+1就能加入结果中

优化:再次优化,发现之前的j不需要每次都从当前i这个位置进行后续判断,可以采用滑动窗口的思想去处理这个题目,j不需要回退

之前写的题都是控制右窗口,这次使用控制左窗口,固定左边界,

cpp 复制代码
class Solution {
public:
    long long countSubarrays(vector<int>& nums, int k) {
        long long res = 0;
        int mx = *max_element(nums.begin(), nums.end()); // 获取数组中的最大值
        int cnt = 0, n = nums.size();
        for(int i = 0, j = 0; i < n; i++) // 控制左端点
        {
            while(j < n && cnt < k)  // 进窗口
            {                        // 让j去往右访问,当j到达边界或者最大值出现了k次时停下
                if(nums[j] == mx)
                    cnt++;
                j++;
            }
            if(cnt == k)
                res += n-j+1;        // 维护结果 j之后的所有数组都满足条件
            if(nums[i] == mx)        // 出窗口 左端点进行出窗口
                cnt--;
        }
        return res;
    }
};

采用固定右边界的方式:不需要一些多余的判断

cpp 复制代码
class Solution {
public:
    long long countSubarrays(vector<int>& nums, int k) {
        // unordered_map<int,int> window;
        int left = 0, right = 0, n = nums.size();
        int cnt = 0, mx = *max_element(nums.begin(), nums.end());
        long long res = 0;
        while(right < n)  // 这次采用固定右端点,维护所有左边界
        {
            if(nums[right] == mx) // 入窗口
                cnt++;
            while(cnt >= k)        // left到right内部都是符合条件的
            {                       // 所以让left到达一个临界点
                if(nums[left] == mx)
                    cnt--;
                left++;
            }
            res += left;     // 保存left之前所有符合条件的结果
            right++;
        }
        return res;
    }
};

由于子数组越长,包含的元素越多,越能满足题目要求;反之,子数组越短,包含的元素越少,越不能满足题目要求。有这种性质的题目,可以用滑动窗口解决。

相关推荐
suhan13 分钟前
【数据结构】三、栈和队列:6.链队列、双端队列、队列的应用(树的层次遍历、广度优先BFS、先来先服务FCFS)
数据结构·后端·算法
姜鱼问生18 分钟前
Docker Volume 备份与恢复实战:不停机迁移数据
后端·算法·架构
suhan19 分钟前
【数据结构】三、栈和队列:5.顺序队列(循环队列)(初始化,判空判满,入队,出队,实例)
数据结构·后端·算法
suhan19 分钟前
【数据结构】三、栈和队列:3.链栈(链栈栈的初始化,判空,进栈,出栈,读取栈顶,链栈实例)
数据结构·后端·算法
大雄很用心20 分钟前
如何理解时间复杂度与空间复杂度?| 面试刷题笔记02
算法
姜鱼问生21 分钟前
服务器磁盘满了?从告警到清理的完整排查
后端·算法·架构
suhan22 分钟前
【数据结构】三、栈和队列:4.栈的应用(括号匹配,四则运算表达式求值,进制转换,递归)
数据结构·后端·算法
suhan30 分钟前
【数据结构】三、栈和队列:2.顺序栈&共享栈(顺序栈的初始化,判空,进栈,出栈,读取栈顶,顺序栈实例)
数据结构·后端·算法
iCxhust35 分钟前
Matlab求解发电机的极限切除角
开发语言·算法·matlab·电力系统
AI语宙漫游指南37 分钟前
RAG 向量检索(上):从 FLAT 到 IVF,查得快为何可能漏?
后端·算法