• 图解LeetCode——1224. 最大相等频率(难度:困难)


    一、题目

    给你一个正整数数组 nums,请你帮忙从该数组中找出能满足下面要求的 最长 前缀,并返回该前缀的长度:

    从前缀中 恰好删除一个 元素后,剩下每个数字的出现次数都相同。

    如果删除这个元素后没有剩余元素存在,仍可认为每个数字都具有相同的出现次数(也就是 0 次)。

    二、示例

    2.1> 示例 1:

    【输入】nums = [2,2,1,1,5,3,3,5]
    【输出】7
    【解释】对于长度为 7 的子数组 [2,2,1,1,5,3,3],如果我们从中删去 nums[4] = 5,就可以得到 [2,2,1,1,3,3],里面每个数字都出现了两次。

    2.2> 示例 2:

    【输入】nums = [1,1,1,2,2,2,3,3,3,4,4,4,5]
    【输出】13

    提示:

    • 2 <= nums.length <= 10^5
    • 1 <= nums[i] <= 10^5

    三、解题思路

    根据题目描述,我们需要找到一个最长的前缀,这个前缀要满足剩下的每个数字出现的次数都相同,那么我们其实可以根据这种要求来归类一下,大致有如下四种类型,是可以满足题目要求的。

    首先,如果我们的前缀字符串都是不同的,并且出现的次数都是一次的话,那么我们无论是删除哪一个元素,剩余的元素的出现次数也都是1次,所以,这种类型我们可以通过计算每个元素的出现次数来做判断。那么,怎么能快速的确定每个元素的出现次数,并且可以快速判断出来出现次数为1的元素个数呢?这里面我们就需要两个变量了,一个用来存储元素它出现次数的关系——elementTimes,另一个用来存储出现了第N次元素的个数——timesGroup。那么当出现了第1次的元素个数等于当前遍历的个数的时候,就表示当前字符串中的元素,满足此类型。关于类型一,请参见下图:

    其次,第二种类型的特征是,只有一个元素出现了N次,而其他的元素都只出现了N-1次。那么当我们将出现了N次的元素移除了一个之后,那么剩余的字符串中的所有元素,出现次数都是N-1次了。这里面我们通过引入一个参数——maxTimes,用于记录最大出现次数。每次遍历元素并计算其出现次数的时候,我们都可以采用Math的max(...)方法来对maxTimes进行同步更新。那么,我们就可以通过获取timesGroup[maxTimes]是否等于1并且计算 timesGroup[maxTimes - 1] * (maxTimes - 1) + 1是否等于遍历的元素个数总和,来确定是否满足类型二的条件。关于类型二,请参见下图:

    那么,第三种类型的特征就是,只有一个元素出现过1次,其他的元素,都出现过N次,那么这时候,当我们移除了仅仅出现过一次的元素时,自然剩下的所有元素,都是出现过N次的。这种情况,我们通过计算出现过N次元素的总和,即:timesGroup[maxTimes] * maxTimes + 1是否等于总遍历元素总和来判断是否满足类型三。关于类型三,请参见下图:

    最后一种类型,就是一个元素出现了N次,并且只有这个元素出现了。那么,针对这种类型,无论去除哪个,结果都是满足条件的。关于类型四,其实在类型二的判断逻辑中,就已经包含了。所以,在代码实现中,就不用单独做处理了。关于类型四,请参见下图:

    四、代码实现

    4.1> 实现1:哈希Map + 最大次数

    1. class Solution {
    2.     public static int maxEqualFreq(int[] nums) {
    3.         /**
    4.          * 情况一:所有元素均出现1次——[1,2,3,4,5,6]
    5.          * 情况二:多个出现N次和1个出现N+1次元素——[1,1,2,2,3,3,3]
    6.          * 情况三:去除1个元素,就满足"最大出现次数"*"元素个数"——[2,2,2,1,1,1,3]、[1,1,1,1,1]、[1,1,1,1,2]
    7.          */
    8.         Map<Integer, Integer> elementTimes = new HashMap(); // 记录元素出现的次数,即:key=[元素1value=[出现2次]
    9.         Map<Integer, Integer> timesGroup = new HashMap(); // 记录某次数中存在的元素个数,即:key=[出现2次] value=[3个元素满足]
    10.         int maxLength = 0, maxTimes = 0;
    11.         for (int i = 0; i < nums.length; i++) {
    12.             int num = elementTimes.getOrDefault(nums[i], 0);
    13.             elementTimes.put(nums[i], num + 1);
    14.             if (num > 0) timesGroup.put(num, timesGroup.get(num) - 1);
    15.             timesGroup.put(num + 1, timesGroup.getOrDefault(num + 10+ 1);
    16.             maxTimes = Math.max(maxTimes, num + 1);
    17.             if (timesGroup.get(1== i + 1 || // 情况一
    18.                     (timesGroup.get(maxTimes) == 1 && maxTimes + timesGroup.get(maxTimes - 1* (maxTimes - 1== i + 1) || // 情况二
    19.                     (maxTimes == i + 1) || // 情况三-1
    20.                     timesGroup.get(maxTimes) * maxTimes == i // 情况三-2
    21.             ) maxLength = i + 1;
    22.         }
    23.         return maxLength;
    24.     }
    25. }

    4.2> 实现2:哈希Map + 最大次数

    1. class Solution {
    2.     public static int maxEqualFreq(int[] nums) {
    3.         /**
    4.          * 情况一:所有元素均出现1次——[1,2,3,4,5,6]
    5.          * 情况二:只有1个元素出现N次 以及 多个出现N次和1个出现N+1次元素——[1,1,1,1]、[1,1,2,2,3,3,3]
    6.          * 情况三:去除1个元素,就满足"最大出现次数"*"元素个数"——[2,2,2,1,1,1,3]、[1,1,1,1,1]、[1,1,1,1,2]
    7.          */
    8.         int[] elementTimes = new int[100001]; // 记录元素出现的次数,即:index=[元素1] elementTimes[index]=[出现2次]
    9.         int[] timesGroup = new int[100001]; // 记录某次数中存在的元素个数,即:index=[出现2次] timesGroup[index]=[3个元素满足]
    10.         Arrays.fill(elementTimes, 0);
    11.         Arrays.fill(timesGroup, 0);
    12.         int maxLength = 0, maxTimes = 0;
    13.         for (int i = 0; i < nums.length; i++) {
    14.             int num = elementTimes[nums[i]];
    15.             elementTimes[nums[i]] += 1;
    16.             if (num > 0) timesGroup[num] += -1;
    17.             timesGroup[num + 1+= 1;
    18.             maxTimes = Math.max(maxTimes, num + 1);
    19.             if (timesGroup[1== i + 1 || // 情况一
    20.                     (timesGroup[maxTimes] == 1 && maxTimes + timesGroup[maxTimes - 1* (maxTimes - 1== i + 1) || // 情况二
    21.                     timesGroup[maxTimes] * maxTimes == i // 情况三
    22.             ) maxLength = i + 1;
    23.         }
    24.         return maxLength;
    25.     }
    26. }

    今天的文章内容就这些了:

    写作不易,笔者几个小时甚至数天完成的一篇文章,只愿换来您几秒钟的 点赞 & 分享 。

    更多技术干货,欢迎大家关注公众号“爪哇缪斯” ~ \(^o^)/ ~ 「干货分享,每天更新」

  • 相关阅读:
    可制造性评估(DFM)
    【数据结构】字符串匹配(暴力匹配)
    御神楽的学习记录之嵌入式Linux(树莓派)环境设置和交叉编译
    Maven 介绍
    【面试必刷TOP101】删除链表的倒数第n个节点 & 两个链表的第一个公共结点
    企业如何确保电子邮件安全?
    Windows 11再次迎来更新,支持1000多款Android应用程序
    Linux系统调优详解(十二)——IO调优之磁盘测速
    Android 弹窗设计规范
    设置小于浏览器默认字体大小的显示方法
  • 原文地址:https://blog.csdn.net/qq_26470817/article/details/126412084