Description:
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.
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.
My Solution:
class Solution {
public int findShortestSubArray(int[] nums) {
Map<Integer,Integer>map = new HashMap<Integer,Integer>();
int len = nums.length;
for(int i = 0;i < len;i++){
map.put(nums[i],(map.get(nums[i]) == null)?0:map.get(nums[i])+1);
}
int maxCount = 0;
List<Integer>list = new ArrayList<Integer>();
for(Integer key : map.keySet()){
if(map.get(key) > maxCount){
maxCount = map.get(key);
}
}
for(Integer key : map.keySet()){
if(map.get(key) == maxCount){
list.add(key);
}
}
List<Integer> temp = new ArrayList<Integer>();
for(int i:nums){
temp.add(Integer.valueOf(i));
}
int shortest = temp.lastIndexOf(list.get(0)) - temp.indexOf(list.get(0)) + 1;
for(int i = 0;i < list.size();i++){
int first = temp.indexOf(list.get(i));
int last = temp.lastIndexOf(list.get(i));
int length = last - first +1;
if(length < shortest){
shortest = length;
}
}
return shortest;
}
}
Better Solution:
class Solution {
public int findShortestSubArray(int[] nums) {
if (nums.length == 0 || nums == null) return 0;
Map<Integer, int[]> map = new HashMap<>();
for (int i = 0; i < nums.length; i++){
if (!map.containsKey(nums[i])){
map.put(nums[i], new int[]{1, i, i}); // the first element in array is degree, second is first index of this key, third is last index of this key
} else {
int[] temp = map.get(nums[i]);
temp[0]++;
temp[2] = i;
}
}
int degree = Integer.MIN_VALUE, res = Integer.MAX_VALUE;
for (int[] value : map.values()){
if (value[0] > degree){
degree = value[0];
res = value[2] - value[1] + 1;
} else if (value[0] == degree){
res = Math.min( value[2] - value[1] + 1, res);
}
}
return res;
}
}
Best Solution:
class Solution {
public int findShortestSubArray(int[] nums) {
if (nums == null || nums.length == 0)
return 0;
int maxNum = 0;
for (int n : nums){
maxNum = Math.max(n, maxNum);
}
//由于数组的元素都为正整数,因此int[maxNum + 1]的下标可以包含数组中所有元素
//start以nums的元素为下标,保存对应的起始点
int[] start = new int[maxNum + 1];
//end以nums的元素为下标,保存对应的终止点
int[] end = new int[maxNum + 1];
//que以nums的元素为下标,保存对应的次数
int[] que = new int[maxNum + 1];
for (int i = 0; i < nums.length; i++){
//第一次出现nums[i]时,将i存入start,即起始点
if (que[nums[i]] == 0)
start[nums[i]] = i;
//每次出现同一个nums元素,更新end数组,即终止点
end[nums[i]] = i;
//每次出现同一个nums元素,更新que数组,计数
que[nums[i]]++;
}
int max = 0;
//找出最大degree
for (int n : que)
max = Math.max(max, n);
List<Integer> maxNums = new ArrayList<>();
#找出que中拥有最大计数的下标
for (int i = 0; i < que.length; i++){
if (que[i] == max)
maxNums.add(i);
}
int res = nums.length;
#遍历maxNums,找出满足degree的最小子集长度
for (int n : maxNums){
int r = end[n] - start[n] + 1;
res = Math.min(r, res);
}
return res;
}
}