题目描述
给定一个非空且只包含非负数的整数数组 nums,数组的度的定义是指数组里任一元素出现频数的最大值。
你的任务是在 nums 中找到与 nums 拥有相同大小的度的最短连续子数组,返回其长度。
示例 1:
输入:[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:输入:[1,2,2,3,1,4,2]
输出:6
提示:nums.length 在1到 50,000 区间范围内。
nums[i] 是一个在 0 到 49,999 范围内的整数。
我的解题思路:遍历数组,统计每个数字出现的频率次数,再找到频率最高的一个或者多个数字的频率数值 用List集合存放该数字,遍历拥有这个数字的List集合,找到该数字第一次出现和最后一次出现的位置,相减+1即为题目要求的度长度。其中统计数字出现频率次数我用了两种方式:一、长度为50000的数组,二、用map哈希表存放
一:数组方式
public int findShortestSubArray(int[] nums) {
int[] array = new int[50000];
for (int i = 0; i < nums.length; i++) {
array[nums[i]]++;
}
List<Integer> list = new ArrayList<>();
int maxNum = 1;
for (int i = 0; i < array.length; i++) {
if (array[i] > maxNum) {
maxNum = array[i];
list.clear();
list.add(i);
} else if (array[i] == maxNum) {
list.add(i);
}
}
int len = Integer.MAX_VALUE;
while (list.size() != 0) {
int num = list.get(0);
int first = 0, second = 0;
boolean flag = true;
for (int i = 0; i < nums.length; i++) {
int temp = nums[i];
if (temp == num && flag) {
first = i;
second = i;
flag = false;
} else if (temp == num) {
second = i;
}
}
int tempLen = second - first + 1;
if (tempLen < len) {
len = tempLen;
}
list.remove(list.get(0));
}
return len;
}
二:哈希表方式
public int findShortestSubArray(int[] nums) {
Map<Integer,Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int count = map.containsKey(nums[i]) ? map.get(nums[i]) : 0;
map.put(nums[i], count + 1);
}
List<Integer> list = new ArrayList<>();
int maxNum = 1;
for(Map.Entry<Integer,Integer> entry : map.entrySet()){
Integer mapKey = entry.getKey();
Integer mapValue = entry.getValue();
if (mapValue > maxNum) {
maxNum = mapValue;
list.clear();
list.add(mapKey);
} else if (mapValue == maxNum) {
list.add(mapKey);
}
}
int len = Integer.MAX_VALUE;
while (list.size() != 0) {
int num = list.get(0);
int first = 0, second = 0;
boolean flag = true;
for (int i = 0; i < nums.length; i++) {
if (nums[i] == num && flag) {
first = i;
second = i;
flag = false;
} else if (nums[i] == num) {
second = i;
}
}
int tempLen = second - first + 1;
if (tempLen < len) {
len = tempLen;
}
list.remove(list.get(0));
}
return len;
}
官方解答:基本思路一致,但可用哈希表,用value记录每一个数映射到一个长度为 3 的数组,数组中的三个元素分别代表这个数出现的次数、这个数在原数组中第一次出现的位置和这个数在原数组中最后一次出现的位置即可。最后遍历哈希表,找到元素出现次数最多,且前后位置差最小的数。
class Solution {
public int findShortestSubArray(int[] nums) {
Map<Integer,int[]> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
if (map.containsKey(nums[i])) {
map.get(nums[i])[0]++; // 次数加一
map.get(nums[i])[2] = i; // 末次位置更改
} else {
map.put(nums[i], new int[]{1, i, i}); // 出现次数,首次位置,末次位置
}
}
int maxNum = 0, minLen = 0;
for (Map.Entry<Integer,int[]> entry : map.entrySet()) {
if (entry.getValue()[0] > maxNum) { // 出现更频繁数字
maxNum = entry.getValue()[0]; // 更改最大频次
minLen = entry.getValue()[2] - entry.getValue()[1] + 1; // 更新最小长度
} else if (entry.getValue()[0] == maxNum) { // 出现频次相同数字
if (entry.getValue()[2] - entry.getValue()[1] + 1 < minLen) { // 比较出现位置长度
minLen = entry.getValue()[2] - entry.getValue()[1] + 1; // 更新最小长度
}
}
}
return minLen;
}
}
复杂度分析
时间复杂度:O(n),其中 n是原数组的长度,我们需要遍历原数组和哈希表各一次,它们的大小均为 O(n)。
空间复杂度:O(n),其中 n是原数组的长度,最坏情况下,哈希表和原数组等大。
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/degree-of-an-array/solution/shu-zu-de-du-by-leetcode-solution-ig97/