贪心题目:数组大小减半

文章目录

题目

标题和出处

标题:数组大小减半

出处: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 ≤ arri ≤ 10 5 \texttt{1} \le \texttt{arri} \le \texttt{10}^\texttt{5} 1≤arri≤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 中选出的集合的最小元素个数。

代码

java 复制代码
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) 的空间。

相关推荐
漂流瓶jz1 小时前
UVA-1609 不公平竞赛 题解答案代码 算法竞赛入门经典第二版
数据结构·算法·链表·贪心·aoapc·算法竞赛入门经典·uva
伟大的车尔尼3 天前
贪心的概念
数据结构·算法·贪心
吞下星星的少年·-·4 天前
The 2025 ICPC Asia East Continent Online Contest (I) A题(模拟+贪心)
算法·贪心·模拟
OuO-217 天前
笔试强训 Day 44:最小差值、kotori 和素因子、dd 爱科学 1.0
二分查找·动态规划·贪心·模拟·记忆化搜索·递归·状态表示优化
aqiu11111119 天前
【算法刷题】蓝桥杯:怎么倒茶(贪心算法 + 结构体排序)
贪心·排序
Tisfy1 个月前
LeetCode 3016.输入单词需要的最少按键次数 II:排序(贪心)
linux·算法·leetcode·题解·贪心·排序·计数
Tisfy1 个月前
LeetCode 3014.输入单词需要的最少按键次数 I:遍历 / if-else计算(比纯数学公式写起来麻烦但好想)
数学·算法·leetcode·字符串·题解·贪心
qz5zwangzihan11 个月前
题解:Atcoder Beginner Contest abc467 F - Email Scheduling Optimization
c++·贪心·atcoder·平衡树·abc467·abc467_f·fhq-treap
cpp_25012 个月前
P6625 [省选联考 2020 B 卷] 卡牌游戏
数据结构·c++·算法·前缀和·贪心·洛谷题解·省选