[leetcode 周赛 158] 1224 最大相等频率

1224 Maximum Equal Frequency最大相等频率

问题描述

给出一个正整数数组 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

  • 示例 3:

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

  • 示例 4:

输入:nums = [10,2,8,9,3,8,1,5,2,3,7,6]
输出:8

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

思路

  • 读题
    前缀: 前n个元素
    符合条件: 元素频次都相同, 只有一个不同

找规律

四种情况:

  1. 数字有两种分类, 第一类频次相等, 第二类比第一类频次多1, 并且第二类只有一个数字 --> [1,1,1,2,2,3,3]
  2. 数字有两种分类, 第一类频次相等, 第二类频次为1, 并且第二类只有一个数字 --> [1,1,2,2,3]
  3. 数字只有一类, 全重复 --> [1,1,1,1]
  4. 数字只有一类, 全不重复 --> [1,2,3,4]

记录下数字出现频次和出现频次的出现频次

  • 示例: nums = [2,2,1,1,5,3,3,5]
    4_4env

代码实现

找规律 多情况分析

class Solution {
    /**
     * 数据量最大界限
     */
    private final static int SIZE = (int) 1e5 + 50;

    public int maxEqualFreq(int[] nums) {
        // freq of number 出现数字的频次
        int[] freqOfNum = new int[SIZE];
        // freq of number's freq 出现数字频次的频次
        int[] freqOfFreq = new int[SIZE];
        // maxFreq 数字出现频次的最大值
        int maxFreq = Integer.MIN_VALUE, ans = 0;

        /*
         * 四种情况:
         *  1. 数字有两种分类, 第一类频次相等, 第二类比第一类频次多1, 并且第二类只有一个数字 --> [1,1,1,2,2,3,3]
         *  2. 数字有两种分类, 第一类频次相等, 第二类频次为1, 并且第二类只有一个数字 --> [1,1,2,2,3]
         *  3. 数字只有一类, 全重复   --> [1,1,1,1]
         *  4. 数字只有一类, 全不重复 --> [1,2,3,4]
         */
        for (int i = 0; i < nums.length; i++) {
            freqOfNum[nums[i]]++;
            freqOfFreq[freqOfNum[nums[i]]]++;
            maxFreq = Math.max(freqOfNum[nums[i]], maxFreq);

            // 第一种情况: 最高频次maxFreq出现数为1, 并且次高频次(maxFreq-1)出现数*其频次==i
            //      --> [1,1,1,2,2,3,3] --> {maxFreq:3(1), fof[2]:3, fof[3]:1, i:6}
            boolean one = (freqOfFreq[maxFreq] == 1) && (freqOfFreq[maxFreq - 1] * (maxFreq - 1) + 1 == i + 1);
            // 第二种情况: 最高频次maxFreq出现数*其频次==i
            //      --> [1,1,2,2,3] --> {maxFreq:2, fof[2]:2, i=4}
            boolean two = freqOfFreq[maxFreq] * maxFreq + 1 == i + 1;
            // 第三种情况: 最高频次maxFreq出现数==1 --> [1,1,1,1] --> {maxFreq:4, fof[4]:1}
            //  与第一种情况合并
            boolean thr = freqOfFreq[maxFreq] == 1;
            if (one || two) {
                ans = i + 1;
            }
        }

        // 第四种情况: 最高频次maxFreq==1 --> [1,2,3,4] --> {maxFreq:1, fof[1]:4}
        boolean four = maxFreq == 1;
        if (four) {
            return nums.length;
        }

        return ans;
    }
}

参考资源

第 157 场周赛 全球排名
java题解,让一眼就看懂的算法!算是对 @杨添伦 算法的补充
C++,O(n),考虑四种情况

posted @ 2019-10-15 16:30  slowbird  阅读(727)  评论(0编辑  收藏  举报