Leetcode 697 数组的度

题目定义:

给定一个非空且只包含非负数的整数数组 nums,数组的度的定义是指数组里任一元素出现频数的最大值。
你的任务是在 nums 中找到与 nums 拥有相同大小的度的最短连续子数组,返回其长度。
    
示例 1:
输入:[1, 2, 2, 3, 1]
输出:2
解释:
输入数组的度是2,因为元素1和2的出现频数最大,均为2.
连续子数组里面拥有相同度的有如下所示:
[1, 2, 2, 3, 1], [1, 2, 2, 3], [2, 2, 3, 1], [1, 2, 2], [2, 2, 3], [2, 2]
最短连续子数组[2, 2]的长度为2,所以返回2.
    
示例 2:
输入:[1,2,2,3,1,4,2]
输出:6

题目解析:

​ 这道题目的稍稍有点绕,需要理解两个含义,一个是数组的度,另一个是包含数组的度的最短子数组,稍稍解释下这两个概念题目就很清晰了

  • 数组的度:数组中根据元素进行分组后,出现的次数最大值,对于示例1来说,数组根据元素进行分组的数字为:[1,2,3],数字的出现次数为:[2,2,1],所以数组的度就为2,也就是数字 1 和 2 出现的系数
  • 包含数组的度的最短子数组:题目要求的是与nums拥有相同数组的度的子数组,并且长度最短,根据示例1,包含数组的度的子数组有:[1, 2, 2, 3, 1], [1, 2, 2, 3], [2, 2, 3, 1], [1, 2, 2], [2, 2, 3], [2, 2],长度最短的子数组为:[2,2],所以返回最短子数组的长度:2

方式一(暴力破解):

class Solution {
    private Map<Integer, Integer> map = new HashMap<>();
    private int max = 0;

    public int findShortestSubArray(int[] nums) {
        int res = Integer.MAX_VALUE;
        getMap(nums);
        List<Integer> list = getMax();
        for (Integer num : list) {
            // right - left + 1 表示包含数组的度的子数组长度
            //count 记录当前子数组中出现了被统计数字的次数
            int left = -1, right = 0, count = 0;
            while (right < nums.length) {
                if (nums[right] == num) {
                    if(left == -1)
                        left = right;
                    count++;
                }
                //若出现次数等于数组的度,则计算子数组的大小
                if (count == max) {
                    res = Math.min(res, right - left + 1);
                    break;
                }
                right++;
            }
        }
        return res;
    }

    //根据哈希表获取出现次数最多的数字
    //max 记录数组的度
    private List<Integer> getMax() {
        max = map.values().stream().max(Comparator.naturalOrder()).orElse(0);
        return map.entrySet().stream()
                .filter(e -> e.getValue() == max)
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());
    }

    //哈希表统计每个数字出现的次数
    private void getMap(int[] nums) {
        for (int num : nums) {
            map.put(num, map.getOrDefault(num, 0) + 1);
        }
    }
}

方式二(哈希表记录当前数字的次数,

第一次出现当前数字的下标,最后一次出现次数的下标):

/*
在实际代码中,我们使用哈希表实现该功能,每一个数映射到一个长度为 33 的数组,
数组中的三个元素分别代表这个数出现的次数、这个数在原数组中第一次出现的位置
和这个数在原数组中最后一次出现的位置。当我们记录完所有信息后,我们需要遍历该哈希表,
找到元素出现次数最多,且前后位置差最小的数
*/
class Solution {
    private Map<Integer,int[]> map = new HashMap<>();
    public int findShortestSubArray(int[] nums) {
        getMap(nums);
        int count = 0,res = 0;
        for(Map.Entry<Integer,int[]> entry : map.entrySet()){
            int[] array = entry.getValue();
            if(count < array[0]){
                count = array[0];
                res = array[2] - array[1] + 1;
            }else if(count == array[0]){
                res = Math.min(res,array[2] - array[1] + 1);
            }
        }
        return res;
    }
    private void getMap(int[] nums){
        for(int i = 0; i < nums.length;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});
            }
        }

    }
}

参考:

https://leetcode-cn.com/problems/degree-of-an-array/solution/shu-zu-de-du-by-leetcode-solution-ig97/

posted @ 2021-02-20 15:22  0xHigos  阅读(79)  评论(0编辑  收藏  举报