leetcode-最大相等频率

86 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第19天,点击查看活动详情

题目描述

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

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

 

示例 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:

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

提示:

  • 2 <= nums.length <= 105
  • 1 <= nums[i] <= 105

思路

本题的难点在于,如何快速判断当前这个前缀是否符合条件。
我们定义一个Map:cnt来存储数字key出现的次数,定义一个Map:freq来存储出现次数为key的数字有几个,maxFreq记录出现最多的次数。

有如下4种情况是符合条件的:

  1. maxFreq = 1,此时每个数字都是出现1次,任意删除1个,剩下的出现次数也都是1
  2. freq 只包含1个key
  3. freq 只包含2个key,maxFreq 和 maxFreq -1,且出现maxFreq的数字个数为1,那么只要移除这个数字1次,剩下所有数字出现次数为maxFreq -1
  4. freq 只包含2个key,maxFreq 和 1,且出现1次的数字个数为1,那么只要移除这个只出现1次的数字,剩下所有数字出现次数都是maxFreq

Java版本代码

class Solution {
    public int maxEqualFreq(int[] nums) {
        // 数字key出现的次数
        Map<Integer, Integer> cnt = new HashMap<>();
        // 出现次数为key的数字有几个
        Map<Integer, Integer> freq = new HashMap<>();
        int maxFreq = 0;
        int ans = 1;
        for (int i = 0; i < nums.length; i++) {
            // 如果这个数字出现过,那么需要维护freq,因为这个数字出现的次数+1,所以原始出现次数对应的数字个数要-1
            if (cnt.containsKey(nums[i])) {
                int times = cnt.get(nums[i]);
                if (freq.get(times) == 1) {
                    freq.remove(times);
                } else {
                    freq.put(times, freq.get(times) - 1);
                }
            }
            cnt.put(nums[i], cnt.getOrDefault(nums[i], 0) + 1);
            int times = cnt.get(nums[i]);
            freq.put(times, freq.getOrDefault(times, 0) + 1);
            maxFreq = Integer.max(maxFreq, times);
            // 4种情况是符合条件的:
            // maxFreq = 1,此时每个数字都是出现1次,任意删除1个,剩下的出现次数也都是1
            // freq 只包含1个key
            // freq 只包含2个key,maxFreq 和 maxFreq -1,且出现maxFreq的数字个数为1,那么只要移除这个数字1次,剩下所有数字出现次数为maxFreq -1
            // freq 只包含2个key,maxFreq 和 1,且出现1次的数字个数为1,那么只要移除这个只出现1次的数字,剩下所有数字出现次数都是maxFreq
            // 判断的时候,freq肯定包含key为maxFreq的键值对,这个不需要再次判断
            boolean flag = maxFreq == 1 || (freq.size() == 1 && freq.get(maxFreq) == 1) ||
                    (freq.size() == 2 && freq.containsKey(maxFreq-1) && freq.get(maxFreq) == 1) ||
                    (freq.size() == 2 && freq.containsKey(1) && freq.get(1) == 1);
            if (flag) {
                ans = i + 1;
            }
        }
        return ans;
    }
}