贪心题目:数组大小减半

题目

标题和出处

标题:数组大小减半

出处: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} 1arr.length105
  • arr.length \texttt{arr.length} arr.length 为偶数
  • 1 ≤ arr[i] ≤ 10 5 \texttt{1} \le \texttt{arr[i]} \le \texttt{10}^\texttt{5} 1arr[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) 的空间。

注:下文中的 *** 代表文件名中的组件名称。# 包含:中文-英文对照文档:【***-javadoc-API文档-中文(简体)-英语-对照版.zip】jar包下载地址:【***.jar下载地址(官方地址+国内镜像地址).txt】Maven依赖:【***.jar Maven依赖信息(可用于项目pom.xml).txt】Gradle依赖:【***.jar Gradle依赖信息(可用于项目build.gradle).txt】源代码下载地址:【***-sources.jar下载地址(官方地址+国内镜像地址).txt】# 本文件关键字:中文-英文对照文档,中英对照文档,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册# 使用方法:解压 【***.jar中文文档.zip】,再解压其中的 【***-javadoc-API文档-中文(简体)版.zip】,双击 【index.html】 文件,即可用浏览器打开、进行查看。# 特殊说明:·本文档为人性化翻译,精心制作,请放心使用。·本文档为双语同时展示,一行原文、一行译文,可逐行对照,避免了原文/译文来回切换的麻烦;·有原文可参照,不再担心翻译偏差误导;·边学技术、边学英语。·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等;·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。# 温馨提示:(1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地);(2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

伟大的车尔尼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值