zoukankan      html  css  js  c++  java
  • [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;
        }
    }
  • 相关阅读:
    剑指Offer 30 包含min函数的栈
    剑指Offer 29 顺时针打印矩阵
    剑指Offer 27 二叉树的镜像
    13张动图助你彻底看懂马尔科夫链、PCA和条件概率!
    一位ML工程师构建深度神经网络的实用技巧
    IBM沃森会成为第一个被抛弃的AI技术吗?
    中国最强AI超级服务器问世,每秒提供AI计算2000万亿次
    SAP WM 有无保存WM Level历史库存的Table?
    SAP MM 按采购订单查询付款信息的报表?
    机器学习项目失败的9个原因
  • 原文地址:https://www.cnblogs.com/lz87/p/11669371.html
Copyright © 2011-2022 走看看