Leetcode 697. 数组的度 以及衍生的静态数组和哈希表的何时使用

这篇博客探讨了如何利用数组计数和哈希表解决寻找数组中最短重复子数组的问题。通过三种不同的实现方式——哈希表、静态数组以及哈希加滑动窗口,分析了它们的效率和适用场景。文章指出,在数值范围较小的情况下,静态数组的计数方法通常更优,避免了哈希函数的计算开销和冲突处理。博客还强调了在选择计数方法时应考虑的问题,并提供了相关参考资料。
摘要由CSDN通过智能技术生成

题目链接

题目理解:

初看题意很难理解,但结合实例即可明白所表达意思。我们所要做的即统计出数组中每个元素的频度,得到频度最大的元素,然后找包含这个元素的子数组中长度最短的,很容易知道以这个重复元素为头尾的既是最短的,注意频度最大的元素可能不唯一,所以我们要比较找出对应长度最短的子数组。

具体解法:

哈希表

每一个数映射到一个长度为 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

  1. 「数组计数」 & 「哈希表计数」解法,以及该如何选择两者
  2. 数组的度
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值