Maximum Equal Frequency

hard array hash table frequency

Problem

Given an array nums of positive integers, return the longest possible length of a prefix of nums such that it is possible to remove exactly one element from this prefix so that every number that remains appears the same number of times.

If after removing one element there are no remaining elements, it is still considered that every appearing number has the same number of occurrences (0).

Inputnums = [2, 2, 1, 1, 5, 3, 3, 5]
Output7
For the prefix [2,2,1,1,5,3,3] of length 7, removing one occurrence of 5 leaves 2,1,3 each appearing exactly twice.

def max_equal_freq(nums):
    cnt = {}        # value -> occurrences
    freq = {}       # occurrences -> how many values have it
    ans = 0
    for i, x in enumerate(nums):
        c = cnt.get(x, 0)
        if c:
            freq[c] -= 1
        cnt[x] = c + 1
        freq[c + 1] = freq.get(c + 1, 0) + 1
        L = i + 1
        keys = [k for k, v in freq.items() if v > 0]
        lo, hi = min(keys), max(keys)
        if len(keys) == 1:
            # all equal freq: valid if it is 1 (drop any), or a single value
            ok = lo == 1 or freq[lo] == 1
        else:  # exactly two distinct freqs
            # top freq one above the rest with a single owner, or one
            # lone value of freq 1 sitting on a uniform block
            ok = (hi - lo == 1 and freq[hi] == 1) or (lo == 1 and freq[lo] == 1)
        if ok:
            ans = L
    return ans
function maxEqualFreq(nums) {
  const cnt = new Map();   // value -> occurrences
  const freq = new Map();  // occurrences -> how many values have it
  let ans = 0;
  for (let i = 0; i < nums.length; i++) {
    const x = nums[i];
    const c = cnt.get(x) || 0;
    if (c) freq.set(c, freq.get(c) - 1);
    cnt.set(x, c + 1);
    freq.set(c + 1, (freq.get(c + 1) || 0) + 1);
    const L = i + 1;
    const keys = [];
    for (const k of freq.keys()) if (freq.get(k) > 0) keys.push(k);
    const lo = Math.min(...keys), hi = Math.max(...keys);
    let ok;
    if (keys.length === 1) {
      ok = lo === 1 || freq.get(lo) === 1;
    } else { // exactly two distinct freqs
      ok = (hi - lo === 1 && freq.get(hi) === 1) || (lo === 1 && freq.get(lo) === 1);
    }
    if (ok) ans = L;
  }
  return ans;
}
class Solution {
    public int maxEqualFreq(int[] nums) {
        Map<Integer, Integer> cnt = new HashMap<>();
        Map<Integer, Integer> freq = new HashMap<>();
        int ans = 0;
        for (int i = 0; i < nums.length; i++) {
            int x = nums[i];
            int c = cnt.getOrDefault(x, 0);
            if (c > 0) freq.put(c, freq.get(c) - 1);
            cnt.put(x, c + 1);
            freq.merge(c + 1, 1, Integer::sum);
            int L = i + 1, lo = Integer.MAX_VALUE, hi = 0, distinct = 0;
            for (int k : freq.keySet()) {
                if (freq.get(k) > 0) { distinct++; lo = Math.min(lo, k); hi = Math.max(hi, k); }
            }
            boolean ok;
            if (distinct == 1) {
                ok = lo == 1 || freq.get(lo) == 1;
            } else { // exactly two distinct freqs
                ok = (hi - lo == 1 && freq.get(hi) == 1) || (lo == 1 && freq.get(lo) == 1);
            }
            if (ok) ans = L;
        }
        return ans;
    }
}
int maxEqualFreq(vector<int>& nums) {
    unordered_map<int, int> cnt, freq;
    int ans = 0;
    for (int i = 0; i < (int)nums.size(); i++) {
        int x = nums[i];
        int c = cnt[x];
        if (c) freq[c]--;
        cnt[x] = c + 1;
        freq[c + 1]++;
        int L = i + 1, lo = INT_MAX, hi = 0, distinct = 0;
        for (auto& p : freq)
            if (p.second > 0) { distinct++; lo = min(lo, p.first); hi = max(hi, p.first); }
        bool ok;
        if (distinct == 1)
            ok = lo == 1 || freq[lo] == 1;
        else // exactly two distinct freqs
            ok = (hi - lo == 1 && freq[hi] == 1) || (lo == 1 && freq[lo] == 1);
        if (ok) ans = L;
    }
    return ans;
}
Time: O(n) Space: O(n)