每日leetcode-数组-697. 数组的度
分类:数组-统计数组中的元素
题目描述:
给定一个非空且只包含非负数的整数数组 nums
,数组的度的定义是指数组里任一元素出现频数的最大值。
你的任务是在 nums
中找到与 nums
拥有相同大小的度的最短连续子数组,返回其长度。
解题思路:
本题可以按照两部分求解:
先求原数组的度;
再求与原数组相同度的最短子数组。
求原数组的度
求数组的度,本质还是求各个元素的出现次数,我们可以用 字典(哈希表)计数,字典的 key 是元素,value 是该元素出现的次数。因此,字典中所有 value 的最大值就是数组的度 degreedegree。
求与原数组相同度的最短子数组
要求的子数组的度与原数组相同度的相同,那么该子数组中也得有 degreedegree 个重复的元素。比如对于示例二[1,2,2,3,1,4,2],出现次数最多的元素是 2,它的出现次数为 3, 所以数组的度为 3;我们要求的子数组得有 3 个 2 ,所以最短的子数组是 [2,2,3,1,4,2]。注意到了吗?我们要求的最短子数组的起始和终止位置,由出现次数最多的元素 第一次和最后一次出现的位置 确定。
另外,需要注意的是出现次数最多的元素可能不止一个,比如示例一[1, 2, 2, 3, 1],数字 1 和数字 2 都出现了 2 次。此时,我们必须分别对每个出现次数为 2 的元素(即数字 1 和数字 2 )都求一次包含2个它的最短子数组的长度(分别为5和2),最终对所有最短子数组长度取 minmin,得到结果为 2。
简单的说 就是 要找出数组的众数,并且还有找出众数在数组中第一次出现和最后一次出现的位置,两个位置组成区间长度就是答案, 如果众数不止一个,那么要取区间长度最短那个
class Solution: def findShortestSubArray(self, nums: List[int]) -> int: # 求数组的度,本质还是求各个元素的出现次数,我们可以用 字典(哈希表)计数,字典的 key 是元素,value 是该元素出现的次数。 # 因此,字典中所有 value 的最大值就是数组的度 degree。 left,right=dict(),dict() #使用 left 和 right 分别保存每个元素在数组中第一次出现的位置和最后一次出现的位置 counter = collections.Counter() #使用 counter 保存每个元素出现的次数 for i,num in enumerate(nums): if num not in left: left[num] = i right[num]=i counter[num] +=1 degree = max(counter.values()) #数组的度 degree 等于 counter.values() 的最大值; res = len(nums) # 对counter再次遍历: # 如果元素 k 出现的次数等于 degree,则找出元素 k 最后一次出现的位置 和 第一次出现的位置,计算两者之差+1,即为子数组长度。 # 对所有出现次数等于 degree 的子数组的最短长度,取 min。 for k,v in counter.items(): # 转化成(元素,计数值)组成的列表 if v == degree: res = min(res,right[k]-left[k]+1) return res
时间复杂度:O(N)O(N),因为对数组遍历了一遍,对counter 遍历了两遍。
空间复杂度:O(N)O(N),因为 counter 在最坏情况下会跟 nums 的元素个数相等。