当前位置: 首页 > news >正文

滑动窗口题目:K 个不同整数的子数组

文章目录

  • 题目
    • 标题和出处
    • 难度
    • 题目描述
      • 要求
      • 示例
      • 数据范围
  • 解法
    • 思路和算法
    • 代码
    • 复杂度分析

题目

标题和出处

标题:K 个不同整数的子数组

出处:992. K 个不同整数的子数组

难度

7 级

题目描述

要求

给定一个整数数组 nums\texttt{nums}nums 和一个整数 k\texttt{k}k,返回 nums\texttt{nums}nums 中的好子数组的数目。

好子数组是恰好有 k\texttt{k}k 个不同整数的数组。

  • 例如,[1,2,3,1,2]\texttt{[1,2,3,1,2]}[1,2,3,1,2] 中有 3\texttt{3}3 个不同的整数:1\texttt{1}12\texttt{2}23\texttt{3}3

子数组是数组的连续部分。

示例

示例 1:

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

示例 2:

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

数据范围

  • 1≤nums.length≤2×104\texttt{1} \le \texttt{nums.length} \le \texttt{2} \times \texttt{10}^\texttt{4}1nums.length2×104
  • 1≤nums[i],k≤nums.length\texttt{1} \le \texttt{nums[i], k} \le \texttt{nums.length}1nums[i], knums.length

解法

思路和算法

考虑数组 nums\textit{nums}nums 的下标范围 [start1,end][\textit{start}_1, \textit{end}][start1,end][start2,end][\textit{start}_2, \textit{end}][start2,end] 的两个子数组,其中 start1<start2\textit{start}_1 < \textit{start}_2start1<start2。如果这两个子数组的不同整数个数都是 kkk,则对于任意 start1<start3<start2\textit{start}_1 < \textit{start}_3 < \textit{start}_2start1<start3<start2,下标范围 [start3,end][\textit{start}_3, \textit{end}][start3,end] 的子数组的不同整数个数也是 kkk。理由如下。

已知下标范围 [start1,end][\textit{start}_1, \textit{end}][start1,end] 的子数组和下标范围 [start2,end][\textit{start}_2, \textit{end}][start2,end] 的子数组的不同整数个数都是 kkk。用 k′k'k 表示下标范围 [start3,end][\textit{start}_3, \textit{end}][start3,end] 的子数组的不同整数个数。由于下标范围 [start3,end][\textit{start}_3, \textit{end}][start3,end] 的子数组比下标范围 [start2,end][\textit{start}_2, \textit{end}][start2,end] 的子数组多了下标范围 [start3,start2−1][\textit{start}_3, \textit{start}_2 - 1][start3,start21] 的元素,因此 k′≥kk' \ge kkk。由于下标范围 [start3,end][\textit{start}_3, \textit{end}][start3,end] 的子数组比下标范围 [start1,end][\textit{start}_1, \textit{end}][start1,end] 的子数组少了下标范围 [start1,start3−1][\textit{start}_1, \textit{start}_3 - 1][start1,start31] 的元素,因此 k′≤kk' \le kkk。由于 k′≥kk' \ge kkkk′≤kk' \le kkk 同时成立,因此 k′=kk' = kk=k

因此,以 end\textit{end}end 作为结束下标且有 kkk 个不同整数的子数组的开始下标是连续的。只要得到每个结束下标对应的有 kkk 个不同整数的子数组中的最长子数组和最短子数组,即可得到有 kkk 个不同整数的子数组的数目。

同理可得,当 end1<end2\textit{end}_1 < \textit{end}_2end1<end2 时,以 end1\textit{end}_1end1 作为结束下标且有 kkk 个不同整数的最长子数组的开始下标小于等于以 end2\textit{end}_2end2 作为结束下标且有 kkk 个不同整数的最长子数组的开始下标,以 end1\textit{end}_1end1 作为结束下标且有 kkk 个不同整数的最短子数组的开始下标小于等于以 end2\textit{end}_2end2 作为结束下标且有 kkk 个不同整数的最短子数组的开始下标。

可以使用两个变长滑动窗口实现。用 [start1,end][\textit{start}_1, \textit{end}][start1,end] 表示寻找有 kkk 个不同整数的子数组中的最长子数组的滑动窗口,用 [start2,end][\textit{start}_2, \textit{end}][start2,end] 表示寻找有 kkk 个不同整数的子数组中的最短子数组的滑动窗口,初始时 start1=start2=end=0\textit{start}_1 = \textit{start}_2 = \textit{end} = 0start1=start2=end=0。将两个滑动窗口的右端点 end\textit{end}end 向右移动,移动过程中维护两个滑动窗口的左端点 start1\textit{start}_1start1start2\textit{start}_2start2

使用两个哈希表分别记录两个滑动窗口中的每个元素的出现次数,两个哈希表分别为最长子数组哈希表和最短子数组哈希表。对于每个右端点 end\textit{end}end,执行如下操作。

  1. nums[end]\textit{nums}[\textit{end}]nums[end] 在两个哈希表中的次数各加 111

  2. 如果最长子数组哈希表中的元素个数大于 kkk,则将 nums[start1]\textit{nums}[\textit{start}_1]nums[start1] 在最长子数组哈希表中的次数减 111,如果 nums[start1]\textit{nums}[\textit{start}_1]nums[start1] 在最长子数组哈希表中的次数变成 000 则将 nums[start1]\textit{nums}[\textit{start}_1]nums[start1] 从最长子数组哈希表中删除,然后将 start1\textit{start}_1start1 向右移动一位,重复该操作直到最长子数组哈希表中的元素个数小于等于 kkk

  3. 如果最短子数组哈希表中的元素个数大于等于 kkk,则将 nums[start2]\textit{nums}[\textit{start}_2]nums[start2] 在最短子数组哈希表中的次数减 111,如果 nums[start2]\textit{nums}[\textit{start}_2]nums[start2] 在最短子数组哈希表中的次数变成 000 则将 nums[start2]\textit{nums}[\textit{start}_2]nums[start2] 从最短子数组哈希表中删除,然后将 start2\textit{start}_2start2 向右移动一位,重复该操作直到最短子数组哈希表中的元素个数小于 kkk

  4. 下标范围 [start1,end][\textit{start}_1, \textit{end}][start1,end] 的子数组为以 end\textit{end}end 作为结束下标且有 kkk 个不同整数的最长子数组,下标范围 [start2−1,end][\textit{start}_2 - 1, \textit{end}][start21,end] 的子数组为以 end\textit{end}end 作为结束下标且有 kkk 个不同整数的最短子数组,因此以 end\textit{end}end 作为结束下标且有 kkk 个不同整数的子数组的数目是 start2−start1\textit{start}_2 - \textit{start}_1start2start1,将 start2−start1\textit{start}_2 - \textit{start}_1start2start1 加到答案中。

遍历结束之后,即可得到数组 nums\textit{nums}nums 中的有 kkk 个不同整数的子数组的数目。

实现方面,由于数组 nums\textit{nums}nums 中的元素都是不超过 nums\textit{nums}nums 的长度的正整数,因此可以创建两个长度为 nums\textit{nums}nums 的长度加 111 的数组代替两个哈希表,使用两个计数器分别表示每个哈希表中的元素个数。初始时,计数器的值为 000。每次更新元素在哈希表中的次数之后,需要更新计数器的值,更新方法如下。

  • 当一个元素在哈希表中的次数加 111 之后,如果次数变成 111,则将计数器的值加 111

  • 当一个元素在哈希表中的次数减 111 之后,如果次数变成 000,则将计数器的值减 111

代码

class Solution {public int subarraysWithKDistinct(int[] nums, int k) {int subarrays = 0;int length = nums.length;int[] counts1 = new int[length + 1];int[] counts2 = new int[length + 1];int distinct1 = 0, distinct2 = 0;int start1 = 0, start2 = 0, end = 0;while (end < length) {int curr = nums[end];counts1[curr]++;if (counts1[curr] == 1) {distinct1++;}counts2[curr]++;if (counts2[curr] == 1) {distinct2++;}while (distinct1 > k) {int prev1 = nums[start1];counts1[prev1]--;if (counts1[prev1] == 0) {distinct1--;}start1++;}while (distinct2 >= k) {int prev2 = nums[start2];counts2[prev2]--;if (counts2[prev2] == 0) {distinct2--;}start2++;}subarrays += start2 - start1;end++;}return subarrays;}
}

复杂度分析

  • 时间复杂度:O(n)O(n)O(n),其中 nnn 是数组 nums\textit{nums}nums 的长度。每个滑动窗口的左右端点最多各遍历数组 nums\textit{nums}nums 一次。

  • 空间复杂度:O(n)O(n)O(n),其中 nnn 是数组 nums\textit{nums}nums 的长度。空间复杂度主要取决于哈希表,由于数组 nums\textit{nums}nums 中的元素都是不超过 nums\textit{nums}nums 的长度的正整数,因此每个哈希表中最多有 nnn 个元素。

http://www.dtcms.com/a/462663.html

相关文章:

  • qq网站临时会话静态网站跟动态的区别
  • 阿里云万网建网站家居企业网站建设报价
  • VBA效率大揭秘:选对数据结构,性能飙升300%!
  • LLM 论文精读(九)A Survey of Reinforcement Learning for Large Reasoning Models
  • The “Next“-价值度量与评估
  • 深圳营销网站建设多少钱frontpage网页制作实例
  • 家用电器行业外贸建站世界工厂采购网app
  • synchronized (Java)
  • LINUX——调试器gdb/cgdb的使用
  • GIS实战:投影变换教程与问题解答(上)
  • 项目(3) - LVGL 图形用户界面(GUI)库
  • 长春专业网站推广给我高清电影
  • Redis07-面试题
  • 甘肃省建设社厅网站电商要怎么做起来
  • 做软件常用的网站四川建筑职业技术学院教务网
  • 公司营业执照可以做几个网站微信小程序怎么制作自己的程序
  • 磁悬浮轴承的“眼睛”与“神经”:位移传感原理深度解析
  • Linux小课堂: 从TTY到图形化终端的完整解析
  • 网站带后台免费下载搜图片找原图
  • 网站怎么快速收录wordpress 文件 钩子
  • 互联网科技公司做网站哪家好农场游戏系统开发 网站建设推广
  • PyTorch 模型部署实战:用 Flask 搭图像分类 API
  • 如何进行目的地网站建设东莞厚街创新科技职业学院
  • 网站标题修改重庆网站设计排名
  • 做图表用的网站做网站有什么工具
  • 温州做网站seophp网站开发就业前景
  • 问题记录:一个简单的字符串正则匹配算法引发的 CPU 告警
  • 公共数据资源的“整体授权”是什么涵义?
  • 如何增加网站关键词密度网站建设与维护网课
  • 建立门户网站的程序漳州企业网站建设制作