目录
要解决这个问题,我们需要找到最少需要删除的不同整数集合,使得剩余的元素个数不超过原数组的一半。以下是对该问题的详细分析和解决方案的逐步说明。
问题分析
给定一个整数数组 arr
,要求删除一个元素集合,使得剩余的元素个数 不超过原数组长度的一半 。我们需要找到 删除集合的最小大小。
关键点:
-
删除的元素应尽可能多地减少剩余元素的数量。
-
优先删除出现频率高的元素,可以最快达到目标。
方法思路:贪心算法
贪心算法的核心思想是每一步选择当前最优解,最终得到全局最优解。在本问题中,最优策略是 优先删除出现频率最高的元素,因为这样能快速减少剩余元素的数量。
步骤分解
-
统计频率
遍历数组,用哈希表统计每个元素的出现次数。
例如:数组[3,3,3,3,5,5,5,2,2,7]
的统计结果为:3→4次,5→3次,2→2次,7→1次。 -
按频率降序排序
将哈希表中的频率值提取出来,按从大到小排序。
上例排序后得到[4, 3, 2, 1]
。 -
累加频率直到满足条件
从最高频率开始累加,直到累加值 ≥ 数组长度的一半 。记录累加的步数,即为最少删除的集合大小。
上例中,数组长度n=10
,目标为n/2=5
。累加4+3=7
,只需删除两个元素集合(3和5),剩余元素为7
(即7 ≤5
)。
/**
* @param {number[]} arr
* @return {number}
*/
var minSetSize = function (arr) {
let ans = 0; // 需要删除的元素个数
let sum = 0; // 当前删除的元素个数
const map = new Map();
// 统计每个元素出现的次数
for (let i = 0; i < arr.length; i++) {
map.set(arr[i], (map.get(arr[i]) || 0) + 1);
}
// 将map按出现次数从大到小排序
const sortedMap = Array.from(map.entries()).sort((a, b) => b[1] - a[1]);
console.log(sortedMap);
// 遍历排序后的map,计算需要删除的元素个数
for (let i = 0; i < sortedMap.length; i++) {
// 当前删除的元素个数
sum += sortedMap[i][1];
// 需要删除的元素个数
ans++;
// 如果当前删除的元素个数大于等于数组的一半,则返回需要删除的元素个数
if (sum >= arr.length / 2) {
return ans;
}
}
};
console.log(minSetSize([3, 3, 3, 3, 5, 5, 5, 8, 8, 7]));
代码解释
-
统计频率
-
使用
Map
结构遍历数组,记录每个元素的出现次数。 -
时间复杂度:O(n),其中
n
是数组长度。
-
-
排序频率
-
将频率值转换为数组并按降序排序。
-
时间复杂度:O(k log k),其中
k
是不同元素的数量。
-
-
累加频率
-
依次累加频率值,直到总和 ≥
n/2
。 -
时间复杂度:O(k)。
-
例如:当
sum
达到或超过target
时,立即返回count
。
-
复杂度分析
-
时间复杂度 :O(n + k log k)
其中
n
是数组长度,k
是不同元素的数量。-
统计频率:O(n)
-
排序频率:O(k log k)
-
累加频率:O(k)
-
-
空间复杂度 :O(k)
用于存储哈希表和排序后的频率数组。
正确性证明
贪心策略的正确性可以通过以下思路证明:
-
最优子结构:每次选择频率最高的元素,可以确保每一步删除操作是最优的。
-
反证法:假设存在更优的策略,那么该策略必须包含一个比当前选择的频率更低的元素,但这会导致需要更多的删除次数,与假设矛盾。
示例验证
以输入 [3,3,3,3,5,5,5,2,2,7]
为例:
-
统计频率:3→4,5→3,2→2,7→1。
-
排序频率:[4, 3, 2, 1]。
-
累加过程:
-
第1步:sum=4,count=1(未达到目标5)。
-
第2步:sum=7,count=2(满足条件,返回2)。
-
边界情况
-
所有元素相同
- 输入
[2,2,2,2]
,直接删除集合{2}
(count=1)。
- 输入
-
数组长度为奇数
- 输入
[1,2,3,4,5]
,目标为2.5
,需删除两个元素(例如频率为2和1的元素)。
- 输入
-
恰好达到目标
- 输入
[1,1,1,2,2,3]
,目标为3。删除频率为3和2的元素,sum=3+2=5 ≥3,count=2。
- 输入
总结
通过贪心算法,优先删除高频元素,我们能够以最小的删除次数将数组大小减半。该方法高效且直观,适用于大部分实际场景。