给定一个非空且只包含非负数的整数数组 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 范围内的整数。
链接:https://leetcode-cn.com/problems/degree-of-an-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
package cn.fansunion.leecode.array;
import java.util.HashMap;
import java.util.Map;
/**
* 697. 数组的度 给定一个非空且只包含非负数的整数数组 nums,数组的 度 的定义是指数组里任一元素出现频数的最大值。
*
* 你的任务是在 nums 中找到与 nums 拥有相同大小的度的最短连续子数组,返回其长度。
*
* 来源:力扣(LeetCode) 链接:力扣 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*
* @author wen.lei@brgroup.com
*
* 2022-2-26
*/
public class DegreeOfAnArray {
/*示例 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 范围内的整数。
*/
/**
* 题目的意思有“数组的度”和“最短连续子数组”,概念理解起来较为复杂;<br/>
* 转化下描述:找出出现次数最多的数字,标记起始位和结束位的最小值。 <br/>
* 因为可能存在多个出现次数相同的数字,取(结束位-起始位+1)的最小值。<br/>
* 描述2:找1个覆盖出现次数最多数字的子数组;如果最多数字有多个,找最短的子数组<br/>
* 解法:遍历数字,统计每个数字出现的次数,维护起始位和结束位,最后比较大小
*
* @param nums
* @return
*/
public int findShortestSubArray(int[] nums) {
Map<Integer, NumCountIndex> numCountIndexMap = numCountIndexMap(nums);
//1个数的最大次数(数组的度)
int maxCount = 0;
// 数组的度->最短连续子数组的长度
Map<Integer,Integer> maxCountMinLengthMap=new HashMap<>();
//遍历map,更新最大次数、最小长度和2者的map
for (Map.Entry<Integer, NumCountIndex> entry : numCountIndexMap.entrySet()) {
Integer count = entry.getValue().count;
//最大的次数
if (count >= maxCount) {
maxCount = count;
int maxCountMinLength = maxCountMinLength(maxCountMinLengthMap, entry, count);
maxCountMinLengthMap.put(maxCount, maxCountMinLength);
}
}
return maxCountMinLengthMap.get(maxCount);
}
private int maxCountMinLength(Map<Integer, Integer> maxCountMinLengthMap, Map.Entry<Integer, NumCountIndex> entry,
Integer count) {
//最小的长度
int currentMinLength = entry.getValue().lastIndex - entry.getValue().firstIndex + 1;
Integer length = maxCountMinLengthMap.get(count);
int maxCountMinLength = 0;
if(length==null) {
maxCountMinLength=currentMinLength;
}else {
maxCountMinLength=Math.min(length, currentMinLength);
}
return maxCountMinLength;
}
/**
* 根据数组构造map,维护数字、出现的次数、第1次的index、最后1次的index
* @param nums
* @return
*/
private Map<Integer, NumCountIndex> numCountIndexMap(int[] nums) {
Map<Integer, NumCountIndex> map = new HashMap<>();
for (int index=0;index<nums.length;index++) {
int num=nums[index];
NumCountIndex numCountIndex = map.get(num);
if(numCountIndex==null) {
//第1次初始化
numCountIndex = new NumCountIndex();
numCountIndex.count=1;
numCountIndex.firstIndex=index;
//也需要初始化
numCountIndex.lastIndex=index;
//不关键,本题不需要,习惯性额外维护关键信息
numCountIndex.num=num;
map.put(num, numCountIndex);
}else {
numCountIndex.count++;
numCountIndex.lastIndex=index;
}
}
return map;
}
class NumCountIndex {
int num;
int count;
int firstIndex;
int lastIndex;
@Override
public String toString() {
return "NumCountIndex [num=" + num + ", count=" + count + ", firstIndex=" + firstIndex + ", lastIndex="
+ lastIndex + "]";
}
}
}
package test.leecode.array;
import org.junit.Assert;
import org.junit.Test;
import cn.fansunion.leecode.array.DegreeOfAnArray;
/**
* @author wen.lei@brgroup.com
*
* 2022-2-25
*/
public class DegreeOfAnArrayTest {
@Test
public void test() {
DegreeOfAnArray test = new DegreeOfAnArray();
final int[] nums3 = new int[] {0,1,1,1,12};
Assert.assertEquals(3, test.findShortestSubArray(nums3));
final int[] nums1 = new int[] {0,1,2,3,12};
Assert.assertEquals(1, test.findShortestSubArray(nums1));
final int[] nums11 = new int[] {2};
Assert.assertEquals(1, test.findShortestSubArray(nums11));
final int[] nums2 = new int[] {1, 2, 2, 3, 1};
Assert.assertEquals(2, test.findShortestSubArray(nums2));
final int[] nums31 = new int[] {0,1,1,1,0,0};
Assert.assertEquals(3, test.findShortestSubArray(nums31));
final int[] nums4 = new int[] {0,0,0,0,1};
Assert.assertEquals(4, test.findShortestSubArray(nums4));
final int[] nums41 = new int[] {0,2,0,0,0,1,1,1,1};
Assert.assertEquals(4, test.findShortestSubArray(nums41));
final int[] nums5 = new int[] {0,1,0,1,1,2,1,1,2,2,2,2,3,3,3,3,3};
Assert.assertEquals(5, test.findShortestSubArray(nums5));
final int[] nums6 = new int[] {1,2,2,0,0,1};
Assert.assertEquals(2, test.findShortestSubArray(nums6));
}
}