leetcode
leetcode 2451 ~ 2500
合法分组的最少组数

合法分组的最少组数

难度:

标签:

题目描述

You are given a collection of numbered balls and instructed to sort them into boxes for a nearly balanced distribution. There are two rules you must follow:

  • Balls with the same box must have the same value. But, if you have more than one ball with the same number, you can put them in different boxes.
  • The biggest box can only have one more ball than the smallest box.

​Return the fewest number of boxes to sort these balls following these rules.

 

Example 1:

Input: balls = [3,2,3,2,3]

Output: 2

Explanation:

We can sort balls into boxes as follows:

  • [3,3,3]
  • [2,2]

The size difference between the two boxes doesn't exceed one.

Example 2:

Input: balls = [10,10,10,3,1,1]

Output: 4

Explanation:

We can sort balls into boxes as follows:

  • [10]
  • [10,10]
  • [3]
  • [1,1]

You can't use fewer than four boxes while still following the rules. For example, putting all three balls numbered 10 in one box would break the rule about the maximum size difference between boxes.

 

Constraints:

  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= 109

代码结果

运行时间: 84 ms, 内存: 38.7 MB


/*
 * 思路:
 * 1. 使用流的方式统计每种编号球的数量。
 * 2. 计算每种编号球分配到的最小盒子数。
 * 3. 保证最大盒子的球数比最小盒子多的数目不超过1。
 */
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;

public class Solution {
    public int minBoxes(int[] balls) {
        Map<Integer, Long> countMap = Arrays.stream(balls)
                .boxed()
                .collect(Collectors.groupingBy(ball -> ball, Collectors.counting()));
        return countMap.values().stream()
                .mapToInt(count -> (int) ((count + 1) / 2))
                .max()
                .orElse(0);
    }
}

解释

方法:

此题解首先使用Counter来统计每种编号的球的数量,并将这些数量存储在列表G中。接着将G排序,目的是为了从最小的组开始处理。变量m初始化为G中的最小值,这代表着在迭代过程中尝试的最小盒子大小。接下来,代码通过一个循环不断调整m的值,以找到能满足条件的最小的m。内部循环检查每个g(即每种球的数量)是否能够被当前的m整除,如果不能,就调整m的值。最后,代码计算每种球按照最终确定的m分组后需要的盒子数,累加这些数得到最终结果。

时间复杂度:

O(n + k log k)

空间复杂度:

O(k)

代码细节讲解

🦆
题解中提到`m初始化为G中的最小值`,为什么选择这个起始值,它与最终结果有什么直接关系?
选择G中的最小值作为m的初始值是基于算法效率和逻辑简化的考虑。实际上,最小值提供了一个可能的最小组大小的下界,从而确保我们从可能的最小分组开始探索,逐步增加组大小以找到合适的值。这种方法可以避免在不可能的小组大小上浪费计算资源,因为任何比G中最小数量还小的组大小都不可能合法地分配所有元素。
🦆
在内部循环中,`if g >= m*(m-1)`这个条件是如何确定的,它在算法中起什么作用?
这个条件用于检查当前的分组大小m是否有可能导致非法的分组。如果某个g(即某种球的数量)大于或等于m*(m-1),这意味着当前的分组大小m可能过小,不能有效地分配所有元素。这是一种优化检查,用于避免在不合适的m值上进行过多无效计算。这个条件帮助快速调整m至一个更可能的合理值,以减少不必要的迭代。
🦆
您提到的`q, r = divmod(g, m)`步骤中,为什么通过比较q和r的值来决定是否调整m的大小?这里的逻辑是基于什么考虑?
在这一步中,q代表整除结果,即每组m个元素可以分多少组,而r代表余数,即不能完整形成一组的剩余元素。如果q(完整组数)小于r(剩余元素数),这表明当前的m值过大,导致无法将所有元素均匀分配。因此,需要调整m的值,使得我们可以更合理地分配元素,至少确保每个组中元素的数量不会低于剩余元素的数量。
🦆
题解中调整m值时使用的`m = g//(q+1)`公式是如何得出的?它能确保什么样的结果?
这个公式是在当前m值导致不能均匀分配的情况下调整m的尝试。通过将g除以(q+1),我们试图找到一个新的组大小,这个大小可以使得每组至少分得q+1个元素,从而更加平均地分配剩余的元素。这种调整可以确保每组的元素数量尽可能地接近,避免某些组元素数量过多而其他组过少。这有助于找到一个更合理的m值,以达到更优的分组效果。

相关问题