287、数组的度

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

你的任务是在 nums 中找到与 nums 拥有相同大小的度的最短连续子数组,返回其长度。

  

示例 1

输入:nums = [1,2,2,3,1]

输出:2

解释:

输入数组的度是 2 ,因为元素 1 和 2 的出现频数最大,均为 2 

连续子数组里面拥有相同度的有如下所示:

[12231], [1223], [2231], [122], [223], [22]

最短连续子数组 [22] 的长度为 2 ,所以返回 2 

示例 2

输入:nums = [1,2,2,3,1,4,2]

输出:6

解释:

数组的度是 3 ,因为元素 2 重复出现 3 次。

所以 [2,2,3,1,4,2] 是最短子数组,因此返回 6 

  

提示:

nums.length 在 1 到 50,000 范围内。

nums[i] 是一个在 0 到 49,999 范围内的整数。

来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/degree-of-an-array

著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

package cn.fansunion.leecode.array;

import java.util.HashMap;

import java.util.Map;

/**

 * 697. 数组的度 给定一个非空且只包含非负数的整数数组 nums,数组的 度 的定义是指数组里任一元素出现频数的最大值。

 *

 * 你的任务是在 nums 中找到与 nums 拥有相同大小的度的最短连续子数组,返回其长度。

 *

 * 来源:力扣(LeetCode) 链接:力扣 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

 *

 * @author wen.lei@brgroup.com

 *

 *         2022-2-26

 */

public class DegreeOfAnArray {

    /*示例 1:

     

    输入:nums = [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:

     

    输入:nums = [1,2,2,3,1,4,2]

    输出:6

    解释:

    数组的度是 3 ,因为元素 2 重复出现 3 次。

    所以 [2,2,3,1,4,2] 是最短子数组,因此返回 6 。

      

     

    提示:

     

    nums.length 在 1 到 50,000 范围内。

    nums[i] 是一个在 0 到 49,999 范围内的整数。

    */

    /**

     * 题目的意思有“数组的度”和“最短连续子数组”,概念理解起来较为复杂;<br/>

     * 转化下描述:找出出现次数最多的数字,标记起始位和结束位的最小值。 <br/>

     * 因为可能存在多个出现次数相同的数字,取(结束位-起始位+1)的最小值。<br/>

     * 描述2:找1个覆盖出现次数最多数字的子数组;如果最多数字有多个,找最短的子数组<br/>

     * 解法:遍历数字,统计每个数字出现的次数,维护起始位和结束位,最后比较大小

     *

     * @param nums

     * @return

     */

    public int findShortestSubArray(int[] nums) {

        Map<Integer, NumCountIndex> numCountIndexMap = numCountIndexMap(nums);

        //1个数的最大次数(数组的度)

        int maxCount = 0;

        // 数组的度->最短连续子数组的长度

        Map<Integer,Integer> maxCountMinLengthMap=new HashMap<>();

        //遍历map,更新最大次数、最小长度和2者的map

        for (Map.Entry<Integer, NumCountIndex> entry : numCountIndexMap.entrySet()) {

            Integer count = entry.getValue().count;

            //最大的次数

            if (count >= maxCount) {

                maxCount = count;

                int maxCountMinLength = maxCountMinLength(maxCountMinLengthMap, entry, count);

                maxCountMinLengthMap.put(maxCount, maxCountMinLength);

            }

        }

        return maxCountMinLengthMap.get(maxCount);

    }

    private int maxCountMinLength(Map<Integer, Integer> maxCountMinLengthMap, Map.Entry<Integer, NumCountIndex> entry,

        Integer count) {

        //最小的长度

        int currentMinLength = entry.getValue().lastIndex - entry.getValue().firstIndex + 1;

        Integer length = maxCountMinLengthMap.get(count);

        int maxCountMinLength = 0;

        if(length==null) {

            maxCountMinLength=currentMinLength;

        }else {

            maxCountMinLength=Math.min(length, currentMinLength);

        }

        return maxCountMinLength;

    }

    /**

     * 根据数组构造map,维护数字、出现的次数、第1次的index、最后1次的index

     * @param nums

     * @return

     */

    private Map<Integer, NumCountIndex> numCountIndexMap(int[] nums) {

        Map<Integer, NumCountIndex> map = new HashMap<>();

        for (int index=0;index<nums.length;index++) {

            int num=nums[index];

            NumCountIndex numCountIndex = map.get(num);

            if(numCountIndex==null) {

                //第1次初始化

                numCountIndex = new NumCountIndex();

                numCountIndex.count=1;

                numCountIndex.firstIndex=index;

                //也需要初始化

                numCountIndex.lastIndex=index;

                //不关键,本题不需要,习惯性额外维护关键信息

                numCountIndex.num=num;

                map.put(num, numCountIndex);

            }else {

                numCountIndex.count++;

                numCountIndex.lastIndex=index;

            }

        }

        return map;

    }

    class NumCountIndex {

        int num;

        int count;

        int firstIndex;

        int lastIndex;

        @Override

        public String toString() {

            return "NumCountIndex [num=" + num + ", count=" + count + ", firstIndex=" + firstIndex + ", lastIndex="

                + lastIndex + "]";

        }

         

    }

}

package test.leecode.array;

import org.junit.Assert;

import org.junit.Test;

import cn.fansunion.leecode.array.DegreeOfAnArray;

/**

 * @author wen.lei@brgroup.com

 *

 * 2022-2-25

 */

public class DegreeOfAnArrayTest {

    @Test

    public void test() {

        DegreeOfAnArray test = new DegreeOfAnArray();

        final int[] nums3 = new int[] {0,1,1,1,12};

        Assert.assertEquals(3, test.findShortestSubArray(nums3));

        final int[] nums1 = new int[] {0,1,2,3,12};

        Assert.assertEquals(1, test.findShortestSubArray(nums1));

         

        final int[] nums11 = new int[] {2};

        Assert.assertEquals(1, test.findShortestSubArray(nums11));

         

        final int[] nums2 = new int[] {12231};

        Assert.assertEquals(2, test.findShortestSubArray(nums2));

         

    

        final int[] nums31 = new int[] {0,1,1,1,0,0};

        Assert.assertEquals(3, test.findShortestSubArray(nums31));

         

         

        final int[] nums4 = new int[] {0,0,0,0,1};

        Assert.assertEquals(4, test.findShortestSubArray(nums4));

        final int[] nums41 = new int[] {0,2,0,0,0,1,1,1,1};

        Assert.assertEquals(4, test.findShortestSubArray(nums41));

         

        final int[] nums5 = new int[] {0,1,0,1,1,2,1,1,2,2,2,2,3,3,3,3,3};

        Assert.assertEquals(5, test.findShortestSubArray(nums5));

         

        final int[] nums6 = new int[] {1,2,2,0,0,1};

        Assert.assertEquals(2, test.findShortestSubArray(nums6));

    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值