题目
标题和出处
标题:数组大小减半
出处:1338. 数组大小减半
难度
3 级
题目描述
要求
给定一个整数数组 arr \texttt{arr} arr。可以从中选出一个整数集合,并删除这些整数在数组中的每次出现。
返回至少能删除数组中的一半整数的整数集合的最小元素个数。
示例
示例 1:
输入:
arr
=
[3,3,3,3,5,5,5,2,2,7]
\texttt{arr = [3,3,3,3,5,5,5,2,2,7]}
arr = [3,3,3,3,5,5,5,2,2,7]
输出:
2
\texttt{2}
2
解释:选择
{3,7}
\texttt{\{3,7\}}
{3,7} 将数组变成
[5,5,5,2,2]
\texttt{[5,5,5,2,2]}
[5,5,5,2,2],长度为
5
\texttt{5}
5(原数组长度的一半)。
大小为
2
\texttt{2}
2 的可行集合有
{3,5},{3,2},{5,2}
\texttt{\{3,5\},\{3,2\},\{5,2\}}
{3,5},{3,2},{5,2}。
选择
{2,7}
\texttt{\{2,7\}}
{2,7} 是不可行的,将数组变成
[3,3,3,3,5,5,5]
\texttt{[3,3,3,3,5,5,5]}
[3,3,3,3,5,5,5],其长度大于原数组的一半。
示例 2:
输入:
arr
=
[7,7,7,7,7,7]
\texttt{arr = [7,7,7,7,7,7]}
arr = [7,7,7,7,7,7]
输出:
1
\texttt{1}
1
解释:只能选择集合
{7}
\texttt{\{7\}}
{7},将数组变成空数组。
数据范围
- 1 ≤ arr.length ≤ 10 5 \texttt{1} \le \texttt{arr.length} \le \texttt{10}^\texttt{5} 1≤arr.length≤105
- arr.length \texttt{arr.length} arr.length 为偶数
- 1 ≤ arr[i] ≤ 10 5 \texttt{1} \le \texttt{arr[i]} \le \texttt{10}^\texttt{5} 1≤arr[i]≤105
解法
思路和算法
遍历数组 arr \textit{arr} arr 得到每个元素的出现次数,创建列表 counts \textit{counts} counts 存储每个元素的出现次数,则 counts \textit{counts} counts 中的元素之和为数组 arr \textit{arr} arr 的长度,问题转换成从 counts \textit{counts} counts 中选择最少的元素个数使得所选的元素之和至少为数组 arr \textit{arr} arr 的长度的一半。
根据贪心思想,在所选元素之和下界确定的情况下,为了使所选元素的个数最少,应从 counts \textit{counts} counts 按照从大到小的顺序依次选取元素,直到选取的元素之和至少为数组 arr \textit{arr} arr 的长度的一半,此时选取的元素个数即为从数组 arr \textit{arr} arr 中选出的集合的最小元素个数。
贪心思想的正确性说明如下。
假设从 counts \textit{counts} counts 按照从大到小的顺序选取元素时,至少选取 x x x 个元素可以满足选取的元素之和至少为数组 arr \textit{arr} arr 的长度的一半,用 halfLength \textit{halfLength} halfLength 表示数组 arr \textit{arr} arr 的长度的一半。如果将最大的 x x x 个元素中的任意一个元素换成更小的元素,则选取的元素之和将减小,此时选取的元素之和可能大于等于 halfLength \textit{halfLength} halfLength 也可能小于 halfLength \textit{halfLength} halfLength,如果小于 halfLength \textit{halfLength} halfLength,则需要选取更多元素才能满足选取的元素之和大于等于 halfLength \textit{halfLength} halfLength,此时选取的元素个数大于 x x x。因此按照从大到小的顺序选取元素可以使选取的元素个数最少。
具体做法是,得到列表 counts \textit{counts} counts 之后,将 counts \textit{counts} counts 按降序排序,然后按从大到小的顺序遍历 counts \textit{counts} counts 选取元素,直到选取的元素之和大于等于 halfLength \textit{halfLength} halfLength 时,返回选取的元素个数,即从数组 arr \textit{arr} arr 中选出的集合的最小元素个数。
代码
class Solution {
public int minSetSize(int[] arr) {
Map<Integer, Integer> countsMap = new HashMap<Integer, Integer>();
for (int num : arr) {
countsMap.put(num, countsMap.getOrDefault(num, 0) + 1);
}
List<Integer> counts = new ArrayList<Integer>(countsMap.values());
Collections.sort(counts, (a, b) -> b - a);
int halfLength = arr.length / 2;
int removeCount = 0;
int minSize = 0;
for (int count : counts) {
removeCount += count;
minSize++;
if (removeCount >= halfLength) {
break;
}
}
return minSize;
}
}
复杂度分析
-
时间复杂度: O ( n log n ) O(n \log n) O(nlogn),其中 n n n 是数组 arr \textit{arr} arr 的长度。计算每个元素的出现次数需要 O ( n ) O(n) O(n) 的时间,将出现次数列表排序需要 O ( n log n ) O(n \log n) O(nlogn) 的时间,排序之后遍历出现次数列表需要 O ( n ) O(n) O(n) 的时间,因此时间复杂度是 O ( n log n ) O(n \log n) O(nlogn)。
-
空间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 arr \textit{arr} arr 的长度。哈希表和出现次数列表需要 O ( n ) O(n) O(n) 的空间。
238

被折叠的 条评论
为什么被折叠?



