难度 中等
给你一个整数数组 arr
。你可以从中选出一个整数集合,并删除这些整数在数组中的每次出现。
返回 至少 能删除数组中的一半整数的整数集合的最小大小。
示例 1:
输入:arr = [3,3,3,3,5,5,5,2,2,7]
输出:2
解释:选择 {3,7} 使得结果数组为 [5,5,5,2,2]、长度为 5(原数组长度的一半)。
大小为 2 的可行集合有 {3,5},{3,2},{5,2}。
选择 {2,7} 是不可行的,它的结果数组为 [3,3,3,3,5,5,5],新数组长度大于原数组的二分之一。
示例 2:
输入:arr = [7,7,7,7,7,7]
输出:1
解释:我们只能选择集合 {7},结果数组为空。
示例 3:
输入:arr = [1,9]
输出:1
示例 4:
输入:arr = [1000,1000,3,7]
输出:1
示例 5:
输入:arr = [1,2,3,4,5,6,7,8,9,10]
输出:5
提示:
1 <= arr.length <= 10^5
arr.length
为偶数1 <= arr[i] <= 10^5
审题:
1、arr长度最大为10^5,c申请这么大内存块应该会爆掉
2、arr长度为偶数,因此不需要对长度进行特殊判断,如长度是1
3、返回 至少 能删除数组中的一半整数的整数集合的最小大小:从数组中删除集合中的相同值的元素,使得最多还剩下数组一半的元素,返回的为满足条件的集合中个数最小的一个
思路:
1、对原数组进行排序
2、统计排序后数组个元素的出现的频次,存放在hash表中
3、对hash按照从大到小的顺序进行排序
4、从排序后的hash中查找满足条件的最小个数集合
执行结果:
int CompareBig (const void *a, const void *b)
{
return *(int *)b - *(int *)a;
}
int minSetSize(int* arr, int arrSize){
// 对原数组进行排序
qsort(arr, arrSize, sizeof(int), CompareBig);
/*
for (int i = 0; i < arrSize; i++) {
printf("arr[%d] %d\t", i, arr[i]);
}
printf("\n");
*/
int *hash = (int *)malloc(arrSize * sizeof(int));
memset(hash, 0, arrSize * sizeof(int));
// 统计排序后的数组中元素出现的频次存放在hash表中
int count = 0;
int num = 1;
int i;
for (i = 1; i < arrSize; i++) {
if(i == 1 && arr[i] != arr[i - 1]) {
hash[count++] = 1;
continue;
}
if(arr[i] != arr[i - 1]) {
hash[count++] = num;
num = 1;
}
if(arr[i] == arr[i - 1]) {
num++;
}
if(i == arrSize - 1) {
hash[count++] = num;
}
}
// 对hash表进行从大到小排序
qsort(hash, arrSize, sizeof(int), CompareBig);
/*
for (int i = 0; i < arrSize; i++) {
printf("hash[%d] %d\t", i, hash[i]);
}
printf("\n");
*/
int half = arrSize / 2;
int res = 0;
int sum = 0;
// 统计满足条件的有最小元素个数的集合,并返回该集合中元素的个数
// 由于已从大到小进行排序,因此第一个满足提议条件集合即为结果
for (i = 0; i < arrSize; i++) {
// printf("%d\n", hash[i]);
sum += hash[i];
res++;
if (sum >= half) {
break;
}
}
return res;
}