Easy
题目描述
给定一个由非负整数组成的非空数组 nums,数组的度定义为任何一个元素在数组中出现频次的最大值。
你的任务是在 nums 中找到与 nums 拥有相同度数的最短连续子数组,返回其长度。
示例 1:
输入:nums = [1,2,2,3,1]
输出:2
解释:
输入数组的度是 2,因为元素 1 和 2 的出现次数都是 2 次。
与原数组拥有相同度数的子数组有:
[1, 2, 2, 3, 1], [1, 2, 2, 3], [2, 2, 3, 1], [1, 2, 2], [2, 2, 3], [2, 2]
最短长度是 2,所以返回 2。
示例 2:
输入:nums = [1,2,2,3,1,4,2]
输出:6
解释:
度数是 3,因为元素 2 重复了 3 次。
所以 [2,2,3,1,4,2] 是最短子数组,因此返回 6。
约束条件:
nums.length的范围是 1 到 50,000。nums[i]是范围在 0 到 49,999 的整数。
解题思路
解题思路
这道题需要找到与原数组拥有相同度数的最短连续子数组。关键洞察是:与原数组拥有相同度数的子数组,必须包含所有出现次数等于度数的元素的完整出现。
核心思路:
- 首先统计每个元素的出现次数,找到数组的度(最大出现次数)
- 找出所有出现次数等于度数的元素
- 对于每个这样的元素,计算包含它所有出现位置的最短子数组长度
- 返回所有这些长度中的最小值
算法步骤:
- 用哈希表记录每个数字的出现次数、第一次出现位置、最后一次出现位置
- 遍历一次数组,同时更新这些信息并找到度数
- 再次遍历哈希表,对于出现次数等于度数的元素,计算其子数组长度(最后位置-第一位置+1)
- 返回最小的子数组长度
这种方法只需要遍历数组一次,时间复杂度为O(n),空间复杂度为O(n)。
代码实现
class Solution {
public:
int findShortestSubArray(vector<int>& nums) {
unordered_map<int, int> count, first, last;
for (int i = 0; i < nums.size(); i++) {
int num = nums[i];
count[num]++;
if (first.find(num) == first.end()) {
first[num] = i;
}
last[num] = i;
}
int degree = 0;
for (auto& p : count) {
degree = max(degree, p.second);
}
int minLength = nums.size();
for (auto& p : count) {
if (p.second == degree) {
minLength = min(minLength, last[p.first] - first[p.first] + 1);
}
}
return minLength;
}
};
class Solution:
def findShortestSubArray(self, nums: List[int]) -> int:
count = {}
first = {}
last = {}
for i, num in enumerate(nums):
count[num] = count.get(num, 0) + 1
if num not in first:
first[num] = i
last[num] = i
degree = max(count.values())
min_length = len(nums)
for num, cnt in count.items():
if cnt == degree:
min_length = min(min_length, last[num] - first[num] + 1)
return min_length
public class Solution {
public int FindShortestSubArray(int[] nums) {
Dictionary<int, int> count = new Dictionary<int, int>();
Dictionary<int, int> first = new Dictionary<int, int>();
Dictionary<int, int> last = new Dictionary<int, int>();
for (int i = 0; i < nums.Length; i++) {
int num = nums[i];
count[num] = count.GetValueOrDefault(num, 0) + 1;
if (!first.ContainsKey(num)) {
first[num] = i;
}
last[num] = i;
}
int degree = count.Values.Max();
int minLength = nums.Length;
foreach (var kvp in count) {
if (kvp.Value == degree) {
minLength = Math.Min(minLength, last[kvp.Key] - first[kvp.Key] + 1);
}
}
return minLength;
}
}
/**
* @param {number[]} nums
* @return {number}
*/
var findShortestSubArray = function(nums) {
const count = new Map();
const firstIndex = new Map();
const lastIndex = new Map();
for (let i = 0; i < nums.length; i++) {
const num = nums[i];
count.set(num, (count.get(num) || 0) + 1);
if (!firstIndex.has(num)) {
firstIndex.set(num, i);
}
lastIndex.set(num, i);
}
const degree = Math.max(...count.values());
let minLength = nums.length;
for (const [num, freq] of count) {
if (freq === degree) {
const length = lastIndex.get(num) - firstIndex.get(num) + 1;
minLength = Math.min(minLength, length);
}
}
return minLength;
};
复杂度分析
| 复杂度类型 | 时间复杂度 | 空间复杂度 |
|---|---|---|
| 总体复杂度 | O(n) | O(n) |
说明:
- 时间复杂度: O(n),需要遍历数组一次来统计信息,然后遍历哈希表来找最小长度
- 空间复杂度: O(n),最坏情况下所有元素都不相同,需要存储n个元素的信息
相关题目
- . Maximum Subarray (Medium)