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;
        }
    }
  • 相关阅读:
    洛谷 P2700 逐个击破
    洛谷 P1503 鬼子进村
    洛谷 P1556 幸福的路
    洛谷 P1490 买蛋糕
    洛谷 P2507 [SCOI2008]配对
    code vs 3305 水果姐逛水果街Ⅱ
    通过idea远程调试
    【Cocos2d-x JavaScript Binding】
    ☀【SeaJS】SeaJS Grunt构建
    -_-#【Better Code】throttle / debounce
  • 原文地址:https://www.cnblogs.com/lz87/p/11669371.html
Copyright © 2011-2022 走看看