题目描述
给定一个非空且只包含非负数的整数数组 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 ,所以返回 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
范围内的整数。
题目分析
这道题如果只求数组的度那就很简单的啦,但这里还要求最短连续子数组的长度就稍微有点困难。这里我们同样可以使用哈希表解决,主要的方法就是遍历原数组,记录数组元素的出现次数以及第一次和最后一次出现的位置,然后找出出现次数最多的元素,通过最后一次出现的位置减去第一次出现的位置来获取连续子数组的长度,取最短的长度返回就可以啦。当然,这道题也可以使用滑动窗口的方法求解。下面以题目给的第二个例子为例,大致演示了用哈希表解决该问题的过程。
题解
执行用时: 12 ms
内存消耗: 45.9 MB
class Solution {
public int findShortestSubArray(int[] nums) {
// 创建哈希表 key 为数组出现的元素
// value 为一个数组 数组第一个数存储元素出现的次数
// 数组第二个数存储元素在原数组第一次出现的位置
// 数组第三个数存储元素在原数组最后一次出现的位置
HashMap<Integer, int[]> map = new HashMap<>();
// 获取原数组长度
int length = nums.length;
// 遍历原数组
for (int i = 0; i < length; ++i) {
// 如果 map 中包含当前元素的 key
if (map.containsKey(nums[i])) {
// 更新元素出现的次数
map.get(nums[i])[0]++;
// 更新元素最后出现的位置
map.get(nums[i])[2] = i;
} else {
// map 中没有当前元素的 key
// 添加该 key 出现次数为 1
// 第一次和最后一次出现的位置都是当前位置
map.put(nums[i], new int[]{1, i, i});
}
}
// 原数组的度
int maxDegree = 0;
// 最短连续子数组的长度
int minLength = 0;
// 遍历 map
for (Map.Entry<Integer, int[]> entry : map.entrySet()) {
// 获取 value 数组
int[] value = entry.getValue();
// 如果当前 value 的度大于 maxDegree
if (value[0] > maxDegree) {
// 更新 maxDegree
maxDegree = value[0];
// 更新 minLength 为 最后出现位置 - 第一次出现位置 + 1
minLength = value[2] - value[1] + 1;
} else if (value[0] == maxDegree) {
// 当 value 的度与 maxDegree 相同的情况
// 如果 minLength 大于 当前 value 算出来的连续子数组长度
if (minLength > value[2] - value[1] + 1) {
// 对 minLength 进行更新
minLength = value[2] - value[1] + 1;
}
}
}
// 返回最短连续子数组的长度
return minLength;
}
}
题目来源:力扣(LeetCode)