哈希表题目:数组的度

题目

标题和出处

标题:数组的度

出处:697. 数组的度

难度

4 级

题目描述

要求

给定一个非空且只包含非负数的整数数组 nums \texttt{nums} nums,数组的的定义是指数组中任一元素出现频数的最大值。

你的任务是在 nums \texttt{nums} nums 中找到与 nums \texttt{nums} nums 拥有相同大小的度的最短(连续)子数组的长度。

示例

示例 1:

输入: nums   =   [1,2,2,3,1] \texttt{nums = [1,2,2,3,1]} nums = [1,2,2,3,1]
输出: 2 \texttt{2} 2
解释:
输入数组的度是 2 \texttt{2} 2,因为元素 1 \texttt{1} 1 2 \texttt{2} 2 都出现 2 \texttt{2} 2 次。
度相同的子数组如下:
[1,   2,   2,   3,   1],   [1,   2,   2,   3],   [2,   2,   3,   1],   [1,   2,   2],   [2,   2,   3],   [2,   2] \texttt{[1, 2, 2, 3, 1], [1, 2, 2, 3], [2, 2, 3, 1], [1, 2, 2], [2, 2, 3], [2, 2]} [1, 2, 2, 3, 1], [1, 2, 2, 3], [2, 2, 3, 1], [1, 2, 2], [2, 2, 3], [2, 2]
最短的长度为 2 \texttt{2} 2,所以返回 2 \texttt{2} 2

示例 2:

输入: nums   =   [1,2,2,3,1,4,2] \texttt{nums = [1,2,2,3,1,4,2]} nums = [1,2,2,3,1,4,2]
输出: 6 \texttt{6} 6
解释:
数组的度是 3 \texttt{3} 3,因为元素 2 \texttt{2} 2 出现 3 \texttt{3} 3 次。
所以 [2,2,3,1,4,2] \texttt{[2,2,3,1,4,2]} [2,2,3,1,4,2] 是最短子数组,因此返回 6 \texttt{6} 6

数据范围

  • 1 ≤ nums.length ≤ 5 × 10 4 \texttt{1} \le \texttt{nums.length} \le \texttt{5} \times \texttt{10}^\texttt{4} 1nums.length5×104
  • 0 ≤ nums[i] < 5 × 10 4 \texttt{0} \le \texttt{nums[i]} < \texttt{5} \times \texttt{10}^\texttt{4} 0nums[i]<5×104

解法

思路和算法

由于数组的度为数组中任一元素出现频数的最大值,数组中的任一元素的出现频数都不会超过数组的度。在与数组 nums \textit{nums} nums 拥有相同大小度的子数组中,一定至少包含一个出现频数等于数组的度的元素,且该元素在该子数组中的出现频数等于该元素在数组 nums \textit{nums} nums 中的出现频数,即该子数组包含数组 nums \textit{nums} nums 中的全部该元素。

为了找到与数组 nums \textit{nums} nums 拥有相同大小度的最短子数组的长度,需要记录每个元素在数组 nums \textit{nums} nums 中的出现频数,以及每个元素在数组 nums \textit{nums} nums 中的下标范围(即该元素第一次出现的下标和最后一次出现的下标)。使用两个哈希表分别记录出现频数和下标范围。

遍历数组 nums \textit{nums} nums,对于每个元素,分别更新两个哈希表,同时维护数组的度,如果当前元素的出现频数大于数组的度则将数组的度更新为当前元素的出现频数。遍历结束时,即可得到每个元素的出现频数和下标范围,以及数组的度。

由于数组 nums \textit{nums} nums 满足与其本身拥有相同大小的度,因此将最短子数组的长度初始化为数组 nums \textit{nums} nums 的长度。遍历哈希表中的每个元素,如果一个元素的出现频数等于数组的度,则根据该元素的下标范围计算包含全部该元素的最短子数组的长度(长度计算方法为该元素的最后一次出现的下标和第一次出现的下标之差加 1 1 1),并更新最短子数组的长度。遍历结束之后即可得到与数组 nums \textit{nums} nums 拥有相同大小度的最短子数组的长度。

也可以使用一个哈希表同时记录每个元素的出现频数和下标范围,和使用两个哈希表的做法是等价的。

代码

class Solution {
    public int findShortestSubArray(int[] nums) {
        int degree = 0;
        Map<Integer, Integer> frequencyMap = new HashMap<Integer, Integer>();
        Map<Integer, int[]> rangeMap = new HashMap<Integer, int[]>();
        int length = nums.length;
        for (int i = 0; i < length; i++) {
            int num = nums[i];
            int frequency = frequencyMap.getOrDefault(num, 0) + 1;
            frequencyMap.put(num, frequency);
            degree = Math.max(degree, frequency);
            if (!rangeMap.containsKey(num)) {
                rangeMap.put(num, new int[]{i, i});
            } else {
                rangeMap.get(num)[1] = i;
            }
        }
        int minLength = length;
        Set<Integer> set = frequencyMap.keySet();
        for (int num : set) {
            if (frequencyMap.get(num) == degree) {
                int[] range = rangeMap.get(num);
                minLength = Math.min(minLength, range[1] - range[0] + 1);
            }
        }
        return minLength;
    }
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 nums \textit{nums} nums 的长度。需要遍历数组一次,使用两个哈希表分别记录每个元素出现频数和下标范围,然后遍历两个哈希表计算最短子数组的长度,由于哈希表中的元素个数不超过数组长度,因此时间复杂度是 O ( n ) O(n) O(n)

  • 空间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 nums \textit{nums} nums 的长度。需要使用两个哈希表分别记录每个元素出现频数和下标范围,两个哈希表中的元素个数都不会超过 n n n

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

伟大的车尔尼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值