网站开发与托管协议/微信视频号可以推广吗
题目链接
题目理解:
初看题意很难理解,但结合实例即可明白所表达意思。我们所要做的即统计出数组中每个元素的频度,得到频度最大的元素,然后找包含这个元素的子数组中长度最短的,很容易知道以这个重复元素为头尾的既是最短的,注意频度最大的元素可能不唯一,所以我们要比较找出对应长度最短的子数组。
具体解法:
哈希表
每一个数映射到一个长度为 33 的数组,数组中的三个元素分别代表这个数出现的次数、这个数在原数组中第一次出现的位置和这个数在原数组中最后一次出现的位置。当我们记录完所有信息后,我们需要遍历该哈希表,找到元素出现次数最多,且前后位置差最小的数。
class Solution {public int findShortestSubArray(int[] nums) {Map<Integer,int[]>map=new HashMap<>();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;}
}
静态数组完成哈希表构建
class Solution {int N=50001;public int findShortestSubArray(int[] nums) {int n= nums.length;int[] cnt=new int[N];int[] first=new int[N];//统计开始位置int[] last=new int[N];//统计结束位置Arrays.fill(first,Integer.MAX_VALUE);int max=0;for (int i = 0; i <n; i++) {int t=nums[i];max=Math.max(max,++cnt[t]);first[t]=Math.min(first[t],i);last[t]=Math.max(last[t],i);}int ans=Integer.MAX_VALUE;for (int i = 0; i <n; i++) {int t=nums[i];if(cnt[t]==max) ans=Math.min(ans,last[t]-first[t]+1);}return ans;}
}
哈希+滑动窗口
class Solution {int N=50009;public int findShortestSubArray(int[] nums) {int n= nums.length;int[] cnt=new int[N];int[] first=new int[N];int[] last=new int[N];Arrays.fill(first,Integer.MAX_VALUE);int max=0;for (int i = 0; i <n; i++) {int t=nums[i];max=Math.max(max,++cnt[t]);first[t]=Math.min(first[t],i);last[t]=Math.max(last[t],i);}int ans=Integer.MAX_VALUE;for (int i = 0; i <n; i++) {int t=nums[i];if(cnt[t]==max) ans=Math.min(ans,last[t]-first[t]+1);}return ans;}
}
补充:
哈希表 = 哈希函数 + 数组
由于哈希函数计算需要消耗时间(Java 中首先涉及自动装箱/拆箱,之后还要取对象的 hashCode 进行右移异或,最后才计算哈希桶的下标),以及处理哈希冲突的开销。其效率必然比不上使用我们静态数组进行计数。
对于那些 数值范围确定且不太大(106 以内)的计算场景,使用数组进行计数,而不是使用哈希表。
References
- 「数组计数」 & 「哈希表计数」解法,以及该如何选择两者
- 数组的度