leetcode
leetcode 1251 ~ 1300
数组大小减半

数组大小减半

难度:

标签:

题目描述

代码结果

运行时间: 60 ms, 内存: 32.4 MB


/*
 * 思路:
 * 1. 使用Java Stream计算每个元素的频次。
 * 2. 频次降序排序。
 * 3. 累加最高频次的元素直到覆盖数组的一半。
 * 4. 返回最小集合的大小。
 */
import java.util.*;
import java.util.stream.Collectors;

public class Solution {
    public int minSetSize(int[] arr) {
        Map<Integer, Long> frequencyMap = Arrays.stream(arr)
                .boxed()
                .collect(Collectors.groupingBy(e -> e, Collectors.counting()));
        List<Long> frequencies = frequencyMap.values().stream()
                .sorted(Collections.reverseOrder())
                .collect(Collectors.toList());
        long removed = 0, halfSize = arr.length / 2;
        int setSize = 0;
        for (long freq : frequencies) {
            removed += freq;
            setSize++;
            if (removed >= halfSize) break;
        }
        return setSize;
    }
}

解释

方法:

该题目的核心是找到一个最小的整数集合,使得从数组中删除这些整数后,数组的大小至少减少一半。首先,我们使用 Counter 类来统计数组中每个整数的出现频次。接着,将得到的频次进行降序排序。这样,选择频次最高的数,我们可以更快地减少数组的大小。我们从频次最高的元素开始,逐个累加这些元素的出现次数,直到这个累加值达到或超过原数组长度的一半。此时,累加的元素个数就是所需的最小集合大小。

时间复杂度:

O(n log n)

空间复杂度:

O(n)

代码细节讲解

🦆
在解法中,为什么要选择将频次进行降序排序而不是升序或保持原有顺序?
在解法中选择将频次进行降序排序是为了尽快达到减半数组大小的目标。通过优先选择出现频次最高的元素,可以最快地减少数组中的元素总数,从而用尽可能少的不同元素数量来达到或超过减半的要求。如果使用升序排序或保持原有顺序,则可能需要选择更多的元素才能达到目标,这样做效率较低。
🦆
算法中提到的`累加频次`是否能确保在最坏情况下仍然能够找到满足条件的最小集合?
是的,算法中提到的累加频次能确保在最坏情况下仍能找到满足条件的最小集合。算法通过累加排序后的频次列表,直到累加值达到或超过数组长度的一半。由于排序确保了我们优先考虑出现次数最多的元素,这种方式在任何情况下都可以最小化需要选择的元素集合大小,确保找到的是最小集合。
🦆
如果数组中包含重复元素的数量刚好等于数组长度的一半,算法的输出会是什么?
如果数组中包含的某个重复元素的数量刚好等于数组长度的一半,那么算法的输出将是1。这是因为该元素的出现频次本身就达到了减少数组到一半大小的要求,所以只需选择这一个元素即可实现目标。
🦆
给定`sorted_counts`列表,如果中间某个频次巨大,足以单独满足减半条件,算法是否有机制优化以避免不必要的累加操作?
算法本身在每次累加一个元素的频次后都会检查是否已经达到或超过目标(数组长度的一半)。这意味着一旦发现某个频次足够大,能够单独满足减半条件,算法会立即停止累加并返回当前已选择的元素个数。因此,算法确实有机制优化以避免不必要的累加操作,即通过逐个检查并及时终止循环来实现。

相关问题