Given a non-empty array of non-negative integers nums
, the degree of this array is defined as the maximum frequency of any one of its elements.
Your task is to find the smallest possible length of a (contiguous) subarray of nums
, that has the same degree as nums
.
给定一个非空的非负整数数组nums,数组的度被定义为数组中出现频率最高的元素
你的任务是找到一个与nums度相同的、连续的、且长度最小的nums子数组,并返回子数组的长度
Example 1:
Input: [1, 2, 2, 3, 1]
Output: 2
Explanation:
The input array has a degree of 2 because both elements 1 and 2 appear twice.
Of the subarrays that have the same degree:
[1, 2, 2, 3, 1], [1, 2, 2, 3], [2, 2, 3, 1], [1, 2, 2], [2, 2, 3], [2, 2]
The shortest length is 2. So return 2.
Example 2:
Input: [1,2,2,3,1,4,2]
Output: 6
Note:
nums.length
will be between 1 and 50,000.nums[i]
will be an integer between 0 and 49,999.
Solutions:
Python
'''
首先能想到的就是记录nums中元素出现的次数和起始、终止位置,然后计算起始-终止,取最小的值
且数组的度是与其连续子数组的最大度相同的,所以下面的代码就是根据这个思路写出来的
需要强调一下setdefault函数,setdefault有一个特性,即如果键不在字典中,则添加默认值,
如果键已存在默认值,那么再赋给键默认值,键的默认值不会改变,这样就保证了字典存储的元素位置
永远是元素的起始位置它存储元素起始位置,即使有元素重复,也会记录元素的起始位置不会改变,
'''
(1)
class Solution:
def findShortestSubArray(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
first,dict1 = {},{} #first记录元素出现的其实位置,dict1记录元素出现的次数
degree,res = 0,0 #degree从0开始,增长到nums的度,res是符合条件的子数组的长度
for i,num in enumerate(nums):
first.setdefault(num,i)
dict1[num] = dict1.get(num,0) + 1 #统计元素出现的次数
if dict1[num] > degree: #由于dict1[num]在变化(增大),所以degree需要更新,且degree要保证取最大
degree = dict1[num]
res = i - first[num]+1 #更新子数组长度信息
elif dict1[num] == degree: #当度都一样的时候就比较哪个子数组长度最小,返回最小的
res = min(i-first[num]+1,res)
return res
(2)
'''
这是另外一种解法,其实思路是一样的,只不过它找元素的起始和终止位置的时候有些不同
这个算法是将正序的nums中元素的第一个位置和倒序的nums中元素的第一个位置记下来
然后用数组长度减去这两个位置,就是与nums度相同的子数组的长度
'''
from collections import Counter
class Solution:
def findShortestSubArray(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
if not nums: return 0
c=collections.Counter(nums)
degree,length=max(c.values()),len(nums)
if degree==1: return 1
rnums=list(reversed(nums))
return length-max(nums.index(num)+rnums.index(num) for (num,count) in c.items() if count==degree)
C++
class Solution {
public:
int findShortestSubArray(vector<int>& nums) {
unordered_map<int,int> first,Count;
int length = nums.size();
int degree = 0;
int res = 0;
for (int i=0;i<length;i++){
if (first.count(nums[i]) == 0){
first[nums[i]] = i;
}
Count[nums[i]]++;
if (Count[nums[i]]>degree){
degree = Count[nums[i]];
res = i-first[nums[i]]+1;
}
else if(Count[nums[i]] == degree){
res = min(i-first[nums[i]]+1,res);
}
}
return res;
}
};