• [LeetCode 1224] Maximum Equal Frequency


    Given an array nums of positive integers, return the longest possible length of an array prefix of nums, such that it is possible to remove exactly one element from this prefix so that every number that has appeared in it will have the same number of occurrences.

    If after removing one element there are no remaining elements, it's still considered that every appeared number has the same number of ocurrences (0).

    Example 1:

    Input: nums = [2,2,1,1,5,3,3,5]
    Output: 7
    Explanation: For the subarray [2,2,1,1,5,3,3] of length 7, if we remove nums[4]=5, we will get [2,2,1,1,3,3], so that each number will appear exactly twice.
    

    Example 2:

    Input: nums = [1,1,1,2,2,2,3,3,3,4,4,4,5]
    Output: 13
    

    Example 3:

    Input: nums = [1,1,1,2,2,2]
    Output: 5
    

    Example 4:

    Input: nums = [10,2,8,9,3,8,1,5,2,3,7,6]
    Output: 8
    

    Constraints:

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

    Your solution during contest. 

    Runtime is O(N), space is O(N) as well. But HashMap and HashSet are not as fast as simple array mapping.

    class Solution {
        public int maxEqualFreq(int[] nums) {
            int res = nums.length;
            //m1: number -> its frequency
            Map<Integer, Integer> m1 = new HashMap<>();
            //m2: frequency -> all numbers that have this frequency.
            Map<Integer, Set<Integer>> m2 = new HashMap<>();
            
            //init m1
            for(int i = 0; i < nums.length; i++) {
                m1.put(nums[i], m1.getOrDefault(nums[i], 0) + 1);
            }
            //init m2
            for(int k : m1.keySet()) {
                int v = m1.get(k);
                if(!m2.containsKey(m1.get(k))) {
                    m2.put(v, new HashSet<>());
                }
                m2.get(v).add(k);
            }
            //starting from the longest possible prefix, check if it meets the requirement. If it does, return the current prefix length as result;
            //If it does not, remove the current number from both maps and update the two maps accordingly.
            //Only when we have 1 or 2 unique frequencies in the current prefix window, there is a possible valid solution.
            //2 frequencies: a single number with 1 more occurence that all the rest numbers or a single number with 1 occurence;
            //1 frequency: all numbers with 1 occurence or there is only one number
            for(; res > 1; res--) {
                if(m2.size() == 2) {
                    int maxK = 0, minK = Integer.MAX_VALUE;
                    for(int k : m2.keySet()) {
                        maxK = Math.max(maxK, k);
                        minK = Math.min(minK, k);
                    }
                    if(maxK - minK == 1 && m2.get(maxK).size() == 1 || minK == 1 && m2.get(minK).size() == 1) {
                        break;
                    }
                }
                else if(m2.size() == 1) {
                    int onlyK = 0;
                    for(int k : m2.keySet()) {
                        onlyK = k;
                    }
                    if(onlyK == 1 || m2.get(onlyK).size() == 1) {
                        break;
                    }
                }
                int oldFreq = m1.get(nums[res - 1]);
                int newFreq = oldFreq - 1;
                m1.put(nums[res - 1], newFreq);
                m2.get(oldFreq).remove(nums[res - 1]);
                if(m2.get(oldFreq).size() == 0) {
                    m2.remove(oldFreq);
                }
                if(newFreq > 0) {
                    if(!m2.containsKey(newFreq)) {
                        m2.put(newFreq, new HashSet<>());
                    }
                    m2.get(newFreq).add(nums[res - 1]);                
                }
            }
            return res;
        }
    }

    A much better and cleaner solution.

    cnt[i]: the occurence of number i;

    freq[j]: the total count of different numbers that share the same occurence of j. 

    maxF: the max frequency of all numbers that have been processed.  Only the current visiting number may change maxF. 

    Same with the above solution, there are 4 cases we should consider.

    1. All numbers appear exactly once.  maxF == 1

    2. There is only 1 number appear in the current running window. maxF == i + 1

    3. All numbers appear max_F times, except one number appears once. maxF * freq[maxF] + 1 == i + 1

    4. All numbers appear max_F - 1 times, except one number appears maxF times. (maxF - 1) * freq[maxF - 1] + maxF == i + 1

    Case 1 is actually a special case of case 4 where freq[maxF - 1] = 0. 

    The trick here is to check if the total count of all numbers we've processed is the same length with the current running window. The reason that this works is because we use the max frequency to do the calculation. The only different frequencies we can have is at most 2. If more than 2, using the max frequency in our calculation always generates a greater length than the current window.

    class Solution {
        public int maxEqualFreq(int[] A) {
            int[] cnt = new int[100001], freq = new int[100001];
            int maxF = 0, res = 0;
            for(int i = 0; i < A.length; i++){
                int num = A[i];
                cnt[num]++;
                freq[cnt[num]-1]--;
                freq[cnt[num]]++;
                maxF = Math.max(maxF,cnt[num]);
                if(maxF == 1 || maxF * freq[maxF] + 1 == i + 1 || (maxF - 1) * freq[maxF - 1] + maxF == i + 1) {
                    res = i + 1;
                }                
            }
            return res;
        }
    }
  • 相关阅读:
    如何搭建企业级中台系统
    Linux上安装git
    Jenkins的CI持续集成
    docker安装jenkins
    在线思维导图网站
    K8s容器编排
    MySQL存储引擎
    tomcat8 进入不了Manager App 界面 403 Access Denied
    IdeaVim-常用操作
    Node.js 安装及环境配置之 Windows 篇
  • 原文地址:https://www.cnblogs.com/lz87/p/11669371.html
Copyright © 2020-2023  润新知