方法一:hash表
此方法是工作中时间可以使用的,因为它的时间和空间复杂度都相对平衡,也较低。下面介绍的方法二,工作中是坚决不可以使用的,因为会造成大量的空间浪费。
- 先遍历一遍数组,记录每个元素的出现次数,起始下标和结尾下标
- 然后遍历hash表,找到最大出现次数的元素,然后通过len = 结尾下标 - 起始下标 +1获取其长度
- 如果遇到相同出现次数的元素,选择长度更小的作为答案(题目要求)
class Solution {
public int findShortestSubArray(int[] nums) {
Map<Integer, int[]> map = new HashMap<Integer, int[]>();
int n = nums.length;
for(int i = 0;i < n ; 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()){
int[] arr = entry.getValue();
if(maxNum < arr[0]){
maxNum = arr[0];
minLen = arr[2] - arr[1] +1;
}else if(maxNum == arr[0]){
if(minLen>arr[2] - arr[1] + 1) minLen = arr[2] - arr[1] +1;
}
}
return minLen;
}
}
方法二:数组下标线性索引
此方法的做题效率更高,对于某些题目来说,确实无论是实际应用和做题的角度来说,都是不错的方法。但不是这道题应该使用的方法。对于这道题也只能做题时可以使用一下了。因为它用数组中的值的范围,作为数组x的下标,数组x作为hash表,来进行常数级的存取。但是假设,数组中存储的元素范围是1 ~ 100000000,那么就需要申请长度为100000000的数组空间。假设有一个数组需要处理,[1,2,3,4,4,4,10000000000],如果使用正经的hash表,只需要7个空间。而使用这种方法,空间复杂度就是10000000000。如果实际应用场景你写出这种代码,100%会被辞退的。因此,这个方法,对于这道题,只能大家做题使用,千万不要放到工作场景中。
时间复杂度O(n), 空间复杂度O(maxValue - minValue + 1),空间复杂度是数组中值的取值范围。真的了解一下即可,不推荐使用,纯粹在投机取巧 |
---|
class Solution {
public int findShortestSubArray(int[] nums) {
int min=Integer.MAX_VALUE;
int max=Integer.MIN_VALUE;
for(int i: nums){
max=Math.max(max,i);
min=Math.min(min,i);
}
int[] count=new int[max-min+1];
int maxCount=0;
for(int i:nums){
maxCount=Math.max(maxCount,++count[i-min]);
}
if(maxCount==1){
return 1;
}
int res=nums.length;
int start,end=nums.length-1;
int num=0;
for(int i=0;i<count.length;i++){
if(count[i]!=maxCount){
continue;
}
start=0;
end=nums.length-1;
num=min+i;
while(start<end&&nums[start]!=num){
start++;
}
while(start<end&&nums[end]!=num){
end--;
}
res=Math.min(res,end-start+1);
}
return res;
}
}