贪心题目:数组大小减半

文章目录

题目

标题和出处

标题:数组大小减半

出处: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) 的空间。

相关推荐
伟大的车尔尼4 天前
贪心题目:优势洗牌
贪心
Logic1014 天前
C语言/数据结构动态规划题解:Kadane算法求最大子数组和——O(n)时间O(1)空间
c语言·数据结构·动态规划·贪心·时间复杂度·算法题·最大子数组和
伟大的车尔尼6 天前
贪心题目:分发饼干
贪心
Tisfy7 天前
LeetCode 2472.不重叠回文子字符串的最大数目:动态规划(贪心)
动态规划·字符串·题解·贪心·dp·回文字符串
伟大的车尔尼11 天前
贪心题目:三角形的最大周长
贪心
青少儿编程课堂12 天前
贪心算法进阶:区间调度与最少资源整合解析
c++·python·算法·贪心·信息学竞赛·区间调度
伟大的车尔尼15 天前
贪心题目:保持城市天际线
贪心
a1879272183116 天前
【算法】动态规划第三篇:背包第一课——贪心之死与正序倒序开关
算法·leetcode·动态规划·贪心·dp·暴力·算法讲解
lvwangshu19 天前
P7668 [JOI 2018 Final] 团子制作 / Dango Maker 题解
动态规划·题解·贪心·性质题·思维好题
伟大的车尔尼19 天前
贪心题目:玩筹码
贪心