Hard

题目描述

给你一个正整数数组 nums,请你返回 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

提示:

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

解题思路

这是一道需要仔细分析的哈希表问题。核心思想是跟踪每个数字的出现频率以及频率的分布,判断删除一个元素后是否能使所有数字的频率相同。

我们需要维护两个哈希表:

  • count:记录每个数字的出现次数
  • freqCount:记录每个频率值对应的数字个数

对于每个前缀,删除一个元素后能使所有频率相同的情况有以下几种:

  1. 所有数字频率都是1:删除任意一个数字,其他数字频率仍为1
  2. 只有一个数字频率为1,其他都相同:删除频率为1的数字
  3. 所有数字频率都相同且大于1:删除任意一个数字,该数字频率减1,其他保持不变
  4. 只有一个数字频率比其他数字多1:删除该数字的一个实例
  5. 只有一个数字:删除它后数组为空

通过维护最小频率minFreq和最大频率maxFreq,以及对应的数字个数,我们可以高效判断当前前缀是否满足条件。

时间复杂度为O(n),空间复杂度为O(n)。

代码实现

class Solution {
public:
    int maxEqualFreq(vector<int>& nums) {
        unordered_map<int, int> count;
        unordered_map<int, int> freqCount;
        int maxLen = 0;
        int maxFreq = 0;
        
        for (int i = 0; i < nums.size(); i++) {
            int num = nums[i];
            
            // 更新频率
            if (count[num] > 0) {
                freqCount[count[num]]--;
                if (freqCount[count[num]] == 0) {
                    freqCount.erase(count[num]);
                }
            }
            count[num]++;
            freqCount[count[num]]++;
            maxFreq = max(maxFreq, count[num]);
            
            int len = i + 1;
            
            // 检查是否可以删除一个元素使所有频率相同
            if ((maxFreq == 1) ||  // 所有元素频率都是1
                (freqCount.size() == 1 && ((freqCount.begin()->first == 1) || 
                                           (freqCount.begin()->first * freqCount.begin()->second == len - 1))) || // 只有一种频率
                (freqCount.size() == 2)) {  // 两种频率
                
                if (freqCount.size() == 2) {
                    auto it1 = freqCount.begin();
                    auto it2 = next(it1);
                    int freq1 = it1->first, cnt1 = it1->second;
                    int freq2 = it2->first, cnt2 = it2->second;
                    
                    // 确保freq1 < freq2
                    if (freq1 > freq2) {
                        swap(freq1, freq2); swap(cnt1, cnt2);
                    }
                    
                    // 检查删除一个元素后是否能统一频率
                    if ((freq1 == 1 && cnt1 == 1) ||  // 有一个数字频率为1
                        (freq2 == freq1 + 1 && cnt2 == 1) ||  // 有一个数字频率比其他多1
                        (freq2 == 1 && cnt2 == len - freq1 * cnt1)) {  // 特殊情况
                        maxLen = len;
                    }
                } else {
                    maxLen = len;
                }
            }
        }
        
        return maxLen;
    }
};
class Solution:
    def maxEqualFreq(self, nums: List[int]) -> int:
        count = {}
        freq_count = {}
        max_len = 0
        max_freq = 0
        
        for i, num in enumerate(nums):
            # 更新频率
            if count.get(num, 0) > 0:
                freq_count[count[num]] -= 1
                if freq_count[count[num]] == 0:
                    del freq_count[count[num]]
            
            count[num] = count.get(num, 0) + 1
            freq_count[count[num]] = freq_count.get(count[num], 0) + 1
            max_freq = max(max_freq, count[num])
            
            length = i + 1
            
            # 检查是否可以删除一个元素使所有频率相同
            if (max_freq == 1 or  # 所有元素频率都是1
                len(freq_count) == 1 or  # 只有一种频率
                len(freq_count) == 2):  # 两种频率
                
                if len(freq_count) == 1:
                    freq, cnt = next(iter(freq_count.items()))
                    if freq == 1 or freq * cnt == length - 1:
                        max_len = length
                elif len(freq_count) == 2:
                    freqs = sorted(freq_count.keys())
                    freq1, freq2 = freqs[0], freqs[1]
                    cnt1, cnt2 = freq_count[freq1], freq_count[freq2]
                    
                    if ((freq1 == 1 and cnt1 == 1) or  # 有一个数字频率为1
                        (freq2 == freq1 + 1 and cnt2 == 1) or  # 有一个数字频率比其他多1
                        (freq2 == 1 and cnt2 == length - freq1 * cnt1)):  # 特殊情况
                        max_len = length
                else:  # max_freq == 1
                    max_len = length
        
        return max_len
public class Solution {
    public int MaxEqualFreq(int[] nums) {
        var count = new Dictionary<int, int>();
        var freqCount = new Dictionary<int, int>();
        int maxLen = 0;
        int maxFreq = 0;
        
        for (int i = 0; i < nums.Length; i++) {
            int num = nums[i];
            
            // 更新频率
            if (count.ContainsKey(num) && count[num] > 0) {
                freqCount[count[num]]--;
                if (freqCount[count[num]] == 0) {
                    freqCount.Remove(count[num]);
                }
            }
            
            count[num] = count.GetValueOrDefault(num, 0) + 1;
            freqCount[count[num]] = freqCount.GetValueOrDefault(count[num], 0) + 1;
            maxFreq = Math.Max(maxFreq, count[num]);
            
            int length = i + 1;
            
            // 检查是否可以删除一个元素使所有频率相同
            if (maxFreq == 1 || freqCount.Count == 1 || freqCount.Count == 2) {
                if (freqCount.Count == 1) {
                    var pair = freqCount.First();
                    int freq = pair.Key, cnt = pair.Value;
                    if (freq == 1 || freq * cnt == length - 1) {
                        maxLen = length;
                    }
                } else if (freqCount.Count == 2) {
                    var freqs = freqCount.Keys.OrderBy(x => x).ToArray();
                    int freq1 = freqs[0], freq2 = freqs[1];
                    int cnt1 = freqCount[freq1], cnt2 = freqCount[freq2];
                    
                    if ((freq1 == 1 && cnt1 == 1) ||
                        (freq2 == freq1 + 1 && cnt2 == 1) ||
                        (freq2 == 1 && cnt2 == length - freq1 * cnt1)) {
                        maxLen = length;
                    }
                } else {
                    maxLen = length;
                }
            }
        }
        
        return maxLen;
    }
}
var maxEqualFreq = function(nums) {
    const count = new Map();
    const freqCount = new Map();
    let maxFreq = 0;
    let result = 0;
    
    for (let i = 0; i < nums.length; i++) {
        const num = nums[i];
        
        // Update frequency counts
        if (count.has(num)) {
            const oldFreq = count.get(num);
            freqCount.set(oldFreq, freqCount.get(oldFreq) - 1);
            if (freqCount.get(oldFreq) === 0) {
                freqCount.delete(oldFreq);
            }
        }
        
        const newFreq = (count.get(num) || 0) + 1;
        count.set(num, newFreq);
        freqCount.set(newFreq, (freqCount.get(newFreq) || 0) + 1);
        maxFreq = Math.max(maxFreq, newFreq);
        
        const uniqueNums = count.size;
        const len = i + 1;
        
        // Check valid conditions
        if (
            // All elements appear once
            maxFreq === 1 ||
            // Only one unique number
            uniqueNums === 1 ||
            // All but one number appear maxFreq times, one appears once
            (freqCount.size === 2 && freqCount.has(1) && freqCount.get(1) === 1 && freqCount.get(maxFreq) * maxFreq === len - 1) ||
            // All numbers appear maxFreq times except one appears maxFreq+1 times
            (freqCount.size === 2 && freqCount.has(maxFreq) && freqCount.has(maxFreq - 1) && freqCount.get(maxFreq) === 1) ||
            // All numbers appear the same frequency and removing one element makes it valid
            (freqCount.size === 1 && (maxFreq === 1 || freqCount.get(maxFreq) === 1 || maxFreq * freqCount.get(maxFreq) === len - 1))
        ) {
            result = len;
        }
    }
    
    return result;
};

复杂度分析

复杂度分析
时间复杂度O(n)
空间复杂度O(n)

相关题目