K个不同子数组的数目--滑动窗口--字节--亚马逊

news/2025/2/3 20:14:56 标签: 算法, 数据结构, java

Stay hungry, stay foolish

题目描述

给定一个正整数数组 nums和一个整数 k,返回 nums 中 「好子数组」 的数目。 如果 nums 的某个子数组中不同整数的个数恰好为 k,则称 nums 的这个连续、不一定不同的子数组为 「好子数组 」。 例如,[1,2,3,1,2] 中有 3 个不同的整数:1,2,以及 3。 子数组 是数组的 连续 部分。

输入:nums = [1,2,1,2,3], k = 2
输出:7
解释:恰好由 2 个不同整数组成的子数组:[1,2], [2,1], [1,2], [2,3], [1,2,1], [2,1,2], [1,2,1,2].
输入:nums = [1,2,1,3,4], k = 3
输出:3
解释:恰好由 3 个不同整数组成的子数组:[1,2,1,3], [2,1,3], [1,3,4].

思路分析

问题分解:

  • 我们想要找到所有包含恰好 k 个不同元素的子数组。

  • 但是直接计算恰好 k 个不同元素的子数组比较麻烦,所以我们可以换个思路:先计算所有包含 至多 k 个不同元素的子数组数量,再减去所有包含 至多 k-1 个不同元素的子数组数量。这样就得到了恰好 k 个不同元素的子数组数量。

函数 f(nums, k):

  • 这个函数的作用是计算所有包含 至多 k 个不同元素的子数组数量。

  • 使用两个指针 l 和 r,分别表示当前窗口的左边界和右边界。

  • 使用一个数组 cnts 来记录当前窗口中每个数字的出现次数。

  • 使用一个变量 collect 来记录当前窗口中有多少个不同的数字。

滑动窗口的工作原理:

  • 右指针 r 不断向右移动,每遇到一个新的数字,就更新 cnts 和 collect。

  • 如果 collect 超过了 k,说明当前窗口中的不同数字太多了,需要收缩左指针 l,直到 collect 不再超过 k。

  • 每次右指针 r 移动后,当前窗口中所有以 l 为起点、r 为终点的子数组都是有效的(即包含至多 k 个不同元素),所以把这些子数组的数量累加到结果 ans 中。

最终结果:

  • 通过调用 f(nums, k) 和 f(nums, k - 1),我们得到了包含 至多 k 个不同元素的子数组数量和包含 至多 k-1 个不同元素的子数组数量。

  • 两者相减,就得到了包含 恰好 k 个不同元素的子数组数量。

1. subarraysWithKDistinct 方法:

  • return f(nums, k) - f(nums, k - 1);:计算包含恰好 k 个不同元素的子数组数量。通过计算包含至多 k 个不同元素的子数组数量,减去包含至多 k-1 个不同元素的子数组数量,可以得到恰好 k 个不同元素的子数组数量。

2. f 方法:

  • int ans = 0;:初始化结果变量 ans 为 0,用于存储当前窗口中所有子数组的数量。

  • vector cnts(20001, 0);:初始化一个大小为 20001 的计数数组 cnts,用于记录每个元素的出现次数。假设输入数组中的元素范围在 0 到 20000 之间。

  • for (int l = 0, r = 0, collect = 0; r < arr.size(); r++) {:初始化左指针 l 和右指针 r,以及一个变量 collect 用于记录当前窗口中不同元素的数量。右指针 r 从 0 开始遍历数组。

  • if (++cnts[arr[r]] == 1) { collect++; }:右指针 r 向右移动,并更新计数数组 cnts。如果当前元素 arr[r] 的计数从 0 变为 1,说明这是一个新出现的不同元素,collect 增加 1。

  • while (collect > k) { if (--cnts[arr[l++]] == 0) { collect--; } }:如果当前窗口中不同元素的数量超过 k,左指针 l 向右移动,直到窗口中不同元素的数量不超过 k。在移动左指针 l 时,更新计数数组 cnts,如果某个元素的计数从 1 变为 0,说明这个元素不再出现在当前窗口中,collect 减少 1。

  • ans += r - l + 1;:当前窗口中所有子数组的数量 (从 l 到 r) 都是有效的,累加到结果 ans 中。

  • return ans;:返回结果 ans。

完整代码

class Solution {
public:
    int subarraysWithKDistinct(vector<int>& nums, int k) {
        // 计算包含恰好 k 个不同元素的子数组数量
        // 通过计算包含至多 k 个不同元素的子数组数量,减去包含至多 k-1 个不同元素的子数组数量
        return f(nums, k) - f(nums, k - 1);
    }

    int f(vector<int> arr, int k) {
        // 初始化结果变量 ans 为 0
        int ans = 0;
        // 初始化一个大小为 20001 的计数数组 cnts,用于记录每个元素的出现次数
        vector<int> cnts(20001, 0);
        // 初始化左指针 l 和右指针 r,以及一个变量 collect 用于记录当前窗口中不同元素的数量
        for (int l = 0, r = 0, collect = 0; r < arr.size(); r++) {
            // 右指针 r 向右移动,并更新计数数组和不同元素的数量
            if (++cnts[arr[r]] == 1) {
                collect++;
            }
            // 如果当前窗口中不同元素的数量超过 k,左指针 l 向右移动,直到窗口中不同元素的数量不超过 k
            while (collect > k) {
                if (--cnts[arr[l++]] == 0) {
                    collect--;
                }
            }
            // 当前窗口中所有子数组的数量 (从 l 到 r) 都是有效的,累加到结果 ans 中
            ans += r - l + 1;
        }
        // 返回结果
        return ans;
    }
};

http://www.niftyadmin.cn/n/5841045.html

相关文章

机试题——找磨损度最高和最低的硬盘

题目描述 存储阵列上使用的一批固态硬盘&#xff0c;根据硬盘磨损值给定一个数组 endurances&#xff0c;数组中每个元素表示单块硬盘的磨损度&#xff08;0 到 10000 之间&#xff09;。磨损度越大&#xff0c;表示此盘需要更换的概率越高。需要找出磨损度最高三块盘的下标和…

【4】阿里面试题整理

[1]. 介绍一下数据库死锁 数据库死锁是指两个或多个事务&#xff0c;由于互相请求对方持有的资源而造成的互相等待的状态&#xff0c;导致它们都无法继续执行。 死锁会导致事务阻塞&#xff0c;系统性能下降甚至应用崩溃。 比如&#xff1a;事务T1持有资源R1并等待R2&#x…

Python面试宝典13 | Python 变量作用域,从入门到精通

今天&#xff0c;我们来深入探讨一下 Python 中一个非常重要的概念——变量作用域。理解变量作用域对于编写清晰、可维护、无 bug 的代码至关重要。 什么是变量作用域&#xff1f; 简单来说&#xff0c;变量作用域就是指一个变量在程序中可以被访问的范围。Python 中有四种作…

Flink报错Caused by: java.io.FileNotFoundException: /home/wc.txt

当在提交一个flink任务报如下的错误时&#xff1a; Caused by: java.io.FileNotFoundException: /home/wc.txt (没有那个文件或目录)at java.io.FileInputStream.open0(Native Method)at java.io.FileInputStream.open(FileInputStream.java:195)at java.io.FileInputStream.&…

Dijkstra算法解析

Dijkstra算法&#xff0c;用于求解图中从一个起点到其他所有节点的最短路径。解决单源最短路径问题的有效方法。 条件 有向 带权路径 时间复杂度 O&#xff08;n平方&#xff09; 方法步骤 1 把图上的点分为两个集合 要求的起点 和除了起点之外的点 。能直达的写上权值 不…

基于SpringBoot的美食烹饪互动平台的设计与实现(源码+SQL脚本+LW+部署讲解等)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

80-《红球姜》

红球姜 红球姜&#xff08;学名&#xff1a;Zingiber zerumbet (L.) Smith&#xff09;是姜科姜属多年生草本植物&#xff0c;根茎块状&#xff0c;株高可达2米。叶片披针形至长圆状披针形&#xff0c;无柄或短柄&#xff1b;总花梗长可达30厘米&#xff0c;花序球果状&#xf…

K8s介绍代理外部服务的svc几种方式

在 Kubernetes 中&#xff0c;若需让集群内应用访问外部服务&#xff0c;可通过以下 **Service 配置方式**实现代理&#xff1a; --- ### 1. **ClusterIP Service 手动维护 Endpoints** - **原理**&#xff1a;创建 ClusterIP 类型的 Service 并手动指定 Endpoints&#xff…