首页 > 其他分享 >图解LeetCode——1224. 最大相等频率(难度:困难)

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

时间:2023-05-23 11:02:21浏览次数:42  
标签:1224 int 元素 maxTimes timesGroup num 图解 出现 LeetCode


一、题目

给你一个正整数数组 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次的元素个数等于当前遍历的个数的时候,就表示当前字符串中的元素,满足此类型。关于类型一,请参见下图:

图解LeetCode——1224. 最大相等频率(难度:困难)_字符串

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

图解LeetCode——1224. 最大相等频率(难度:困难)_后端_02

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

图解LeetCode——1224. 最大相等频率(难度:困难)_算法_03

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

图解LeetCode——1224. 最大相等频率(难度:困难)_字符串_04

四、代码实现

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

class Solution {
    public static int maxEqualFreq(int[] nums) {
        /**
         * 情况一:所有元素均出现1次——[1,2,3,4,5,6]
         * 情况二:多个出现N次和1个出现N+1次元素——[1,1,2,2,3,3,3]
         * 情况三:去除1个元素,就满足"最大出现次数"*"元素个数"——[2,2,2,1,1,1,3]、[1,1,1,1,1]、[1,1,1,1,2]
         */
        Map<Integer, Integer> elementTimes = new HashMap(); // 记录元素出现的次数,即:key=[元素1] value=[出现2次]
        Map<Integer, Integer> timesGroup = new HashMap(); // 记录某次数中存在的元素个数,即:key=[出现2次] value=[3个元素满足]
        int maxLength = 0, maxTimes = 0;
        for (int i = 0; i < nums.length; i++) {
            int num = elementTimes.getOrDefault(nums[i], 0);
            elementTimes.put(nums[i], num + 1);

            if (num > 0) timesGroup.put(num, timesGroup.get(num) - 1);
            timesGroup.put(num + 1, timesGroup.getOrDefault(num + 1, 0) + 1);
            maxTimes = Math.max(maxTimes, num + 1);

            if (timesGroup.get(1) == i + 1 || // 情况一
                    (timesGroup.get(maxTimes) == 1 && maxTimes + timesGroup.get(maxTimes - 1) * (maxTimes - 1) == i + 1) || // 情况二
                    (maxTimes == i + 1) || // 情况三-1
                    timesGroup.get(maxTimes) * maxTimes == i // 情况三-2
            ) maxLength = i + 1;
        }
        return maxLength;
    }
}

图解LeetCode——1224. 最大相等频率(难度:困难)_算法_05

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

class Solution {
    public static int maxEqualFreq(int[] nums) {
        /**
         * 情况一:所有元素均出现1次——[1,2,3,4,5,6]
         * 情况二:只有1个元素出现N次 以及 多个出现N次和1个出现N+1次元素——[1,1,1,1]、[1,1,2,2,3,3,3]
         * 情况三:去除1个元素,就满足"最大出现次数"*"元素个数"——[2,2,2,1,1,1,3]、[1,1,1,1,1]、[1,1,1,1,2]
         */
        int[] elementTimes = new int[100001]; // 记录元素出现的次数,即:index=[元素1] elementTimes[index]=[出现2次]
        int[] timesGroup = new int[100001]; // 记录某次数中存在的元素个数,即:index=[出现2次] timesGroup[index]=[3个元素满足]
        Arrays.fill(elementTimes, 0);
        Arrays.fill(timesGroup, 0);

        int maxLength = 0, maxTimes = 0;
        for (int i = 0; i < nums.length; i++) {
            int num = elementTimes[nums[i]];
            elementTimes[nums[i]] += 1;
            if (num > 0) timesGroup[num] += -1;
            timesGroup[num + 1] += 1;
            maxTimes = Math.max(maxTimes, num + 1);
            if (timesGroup[1] == i + 1 || // 情况一
                    (timesGroup[maxTimes] == 1 && maxTimes + timesGroup[maxTimes - 1] * (maxTimes - 1) == i + 1) || // 情况二
                    timesGroup[maxTimes] * maxTimes == i // 情况三
            ) maxLength = i + 1;
        }
        return maxLength;
    }
}

图解LeetCode——1224. 最大相等频率(难度:困难)_后端_06

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

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

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

标签:1224,int,元素,maxTimes,timesGroup,num,图解,出现,LeetCode
From: https://blog.51cto.com/u_15003301/6330124

相关文章

  • 图解LeetCode——769. 最多能完成排序的块(难度:中等)
    一、题目给定一个长度为n的整数数组arr,它表示在[0,n-1]范围内的整数的排列。我们将arr分割成若干块(即分区),并对每个块单独排序。将它们连接起来后,使得连接的结果和按升序排序后的原数组相同。返回数组能分成的最多块数量。二、示例2.1>示例1:【输入】arr=[4,3,2,......
  • 图解LeetCode——940. 不同的子序列 II(难度:困难)
    一、题目给定一个字符串s,计算s的不同非空子序列的个数。因为结果可能很大,所以返回答案需要对10^9+7取余。字符串的子序列是经由原字符串删除一些(也可能不删除)字符但不改变剩余字符相对位置的一个新字符串。例如:"ace"是"abcde"的一个子序列,但"aec"不是。二、示例2.......
  • 图解LeetCode——1441. 用栈操作构建数组(难度:中等)
    一、题目给你一个数组target和一个整数n。每次迭代,需要从 list={1,2,3...,n}中依次读取一个数字。请使用下述操作来构建目标数组target:"Push":从list中读取一个新元素,并将其推入数组中。"Pop":删除数组中的最后一个元素。如果目标数组构建完成,就停止读取更多元......
  • 图解LeetCode——886. 可能的二分法(难度:中等)
    一、题目给定一组 n 人(编号为 1,2,...,n), 我们想把每个人分进任意大小的两组。每个人都可能不喜欢其他人,那么他们不应该属于同一组。给定整数n 和数组dislikes ,其中 dislikes[i]=[ai,bi] ,表示不允许将编号为ai 和  bi的人归入同一组。当可以用这种方法将所有人......
  • 图解LeetCode——827. 最大人工岛(难度:困难)
    给你一个大小为nxn二进制矩阵grid。最多只能将一格 0变成 1。返回执行此操作后,grid中最大的岛屿面积是多少?岛屿由一组上、下、左、右四个方向相连的 1形成。二、示例2.1>示例1:【输入】grid=[[1,0],[0,1]]【输出】3【解释】将一格0变成1,最终连通两个小......
  • 图解LeetCode——904. 水果成篮(难度:中等)
    一、题目你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组fruits表示,其中fruits[i]是第i棵树上的水果种类。你想要尽可能多地收集水果。然而,农场的主人设定了一些严格的规矩,你必须按照要求采摘水果:你只有两个篮子,并且每个篮子只能装单一类型的水果......
  • #yyds干货盘点# LeetCode程序员面试金典:平衡二叉树
    题目:给定一个二叉树,判断它是否是高度平衡的二叉树。本题中,一棵高度平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。 示例1:输入:root=[3,9,20,null,null,15,7]输出:true示例2:输入:root=[1,2,2,3,3,null,null,4,4]输出:false示例3:输入:root=[]......
  • #yyds干货盘点# LeetCode程序员面试金典:分数到小数
    1.简述:给定两个整数,分别表示分数的分子 numerator和分母denominator,以字符串形式返回小数。如果小数部分为循环小数,则将循环的部分括在括号内。如果存在多个答案,只需返回任意一个。对于所有给定的输入,保证答案字符串的长度小于104。 示例1:输入:numerator=1,denominat......
  • LeetCode 103. 二叉树的锯齿形层次遍历
    classSolution{public:vector<vector<int>>res;voidbfs(TreeNode*root){queue<TreeNode*>q;q.push(root);intcnt=0;while(!q.empty()){vector<int>level;......
  • LeetCode 周赛 346(2023/05/21)仅 68 人 AK 的最短路问题
    本文已收录到AndroidFamily,技术和职场问题,请关注公众号[彭旭锐]提问。LeetCode单周赛第345场·体验一题多解的算法之美单周赛345概览T1.删除子串后的字符串最小长度(Easy)标签:栈T2.字典序最小回文串(Medium)标签:贪心、双指针T3.求一个整数的惩罚数(Medium)标签......