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

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

相关推荐
iAkuya6 分钟前
(leetcode)力扣100 62N皇后问题 (普通回溯(使用set存储),位运算回溯)
算法·leetcode·职场和发展
近津薪荼6 分钟前
dfs专题5——(二叉搜索树中第 K 小的元素)
c++·学习·算法·深度优先
xiaoye-duck8 分钟前
吃透 C++ STL list:从基础使用到特性对比,解锁链表容器高效用法
c++·算法·stl
松☆11 分钟前
CANN与大模型推理:在边缘端高效运行7B参数语言模型的实践指南
人工智能·算法·语言模型
java干货22 分钟前
为什么 “File 10“ 排在 “File 2“ 前面?解决文件名排序的终极算法:自然排序
开发语言·python·算法
皮皮哎哟30 分钟前
数据结构:嵌入式常用排序与查找算法精讲
数据结构·算法·排序算法·二分查找·快速排序
程序员清洒38 分钟前
CANN模型剪枝:从敏感度感知到硬件稀疏加速的全链路压缩实战
算法·机器学习·剪枝
vortex51 小时前
几种 dump hash 方式对比分析
算法·哈希算法
堕2741 小时前
java数据结构当中的《排序》(一 )
java·数据结构·排序算法
2302_813806222 小时前
【嵌入式修炼:数据结构篇】——数据结构总结
数据结构