滑动窗口(十五)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;
    }
};

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

相关推荐
JieE21221 小时前
LeetCode 56. 合并区间|超清晰 JS 图解思路,面试高频区间题
javascript·算法·面试
Jack201 天前
HarmonyOS开发中错误处理策略:网络异常统一处理
算法
小小杨树1 天前
读懂色彩:拍照调色不再难
算法·计算机视觉·配色
JieE2122 天前
LeetCode 226. 翻转二叉树|JS 递归超详细拆解,二叉树入门经典题
javascript·算法
JieE2122 天前
LeetCode 104. 二叉树的最大深度|递归思路超详细拆解
javascript·算法
vivo互联网技术2 天前
CVPR 2026 | 全新强化学习框架 BeautyGRPO:重塑真实人像
算法·大模型·cvpr·影像
Darling噜啦啦2 天前
列表转树算法深度解析:从 Map 到 Reduce 的两种实现,面试高频考点
数据结构·算法·面试
用户497863050732 天前
(一)小红的数组操作
算法·编程语言
怕浪猫2 天前
Electron 系列文章封面图
算法·架构·前端框架