leetcode
leetcode 1651 ~ 1700
使数组元素相等的减少操作次数

使数组元素相等的减少操作次数

难度:

标签:

题目描述

代码结果

运行时间: 121 ms, 内存: 26.5 MB


/*
 * 思路:
 * 1. 统计每个数的频率,并按从大到小排序。
 * 2. 使用Java Stream API实现上面的逻辑。
 */

import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;

public class MakeElementsEqualStream {
    public int reductionOperations(int[] nums) {
        Map<Integer, Long> freq = Arrays.stream(nums)
                .boxed()
                .collect(Collectors.groupingBy(e -> e, Collectors.counting()));

        int[] uniqueNums = freq.keySet().stream().sorted().mapToInt(e -> e).toArray();

        int operations = 0;
        for (int i = uniqueNums.length - 1; i > 0; i--) {
            operations += freq.get(uniqueNums[i]) * (i);
            freq.put(uniqueNums[i - 1], freq.get(uniqueNums[i - 1]) + freq.get(uniqueNums[i]));
        }

        return operations;
    }

    public static void main(String[] args) {
        MakeElementsEqualStream solution = new MakeElementsEqualStream();
        int[] nums1 = {5, 1, 3};
        System.out.println(solution.reductionOperations(nums1)); // 输出: 3
        int[] nums2 = {1, 1, 1};
        System.out.println(solution.reductionOperations(nums2)); // 输出: 0
        int[] nums3 = {1, 1, 2, 2, 3};
        System.out.println(solution.reductionOperations(nums3)); // 输出: 4
    }
}

解释

方法:

这个题解首先将数组 nums 中的元素去重并排序,得到一个有序的不重复元素数组 s。然后,使用字典 dt 来映射每个元素在 s 中的索引,这个索引实际上表示的是,从最小值到当前值需要经过多少步骤才能使所有元素变得相等。例如,最小的元素映射到 0,表示不需要任何操作,第二小的元素映射到 1,表示需要一步操作使其降低到最小元素的级别,以此类推。最后,通过遍历原始数组 nums,并使用映射 dt 计算总的操作次数。每个元素的操作次数就是它对应的索引值。

时间复杂度:

O(n + u log u)

空间复杂度:

O(u)

代码细节讲解

🦆
为什么题解中要使用去重并排序的数组s来计算操作次数,而不是直接在原数组nums上操作?
在题解中使用去重并排序的数组s是为了简化操作次数的计算。去重是因为重复的元素在计算变化步骤时会被重复计算,而排序是为了确保从最小元素到最大元素的顺序,使得每个元素到最小元素的操作步数能够直接通过它们的索引差计算得出。如果直接在原数组nums上操作,由于可能包含重复元素且无排序,将难以直接确定每个元素到最小值的确切步骤数。
🦆
在构建映射字典dt时,字典的值是如何确定的,即如何确定每个元素到最小元素的操作步骤数?
在构建映射字典dt时,每个元素的字典值即其在排序后的数组s中的索引。由于s是升序排序的,索引0对应最小元素,索引1对应第二小的元素,依此类推。这样,每个元素的索引值直接表示了将该元素减小到最小元素所需的操作步数(即从该元素减到比它小的下一个元素,一直到最小元素)。
🦆
题解中提到的`从最小值到当前值需要经过多少步骤才能使所有元素变得相等`,这个步骤数是怎样计算的?
这个步骤数是通过元素在排序后的数组s中的位置(索引)来确定的。索引表示了从最小元素到当前元素的顺序位置,每增加一的索引值意味着需要额外一个操作步骤来降低该元素至下一级较小的元素。最终,这个索引值就是从该元素减到最小元素所需的总操作步数。
🦆
如果nums数组中的所有元素已经是相等的,题解的算法是否会进行不必要的计算?
如果nums数组中的所有元素已经相等,去重后的数组s将只包含一个元素,此时该元素的索引为0。构建的映射字典dt将给这个唯一的元素赋值0,表示不需要任何操作。遍历原数组nums时,每个元素的操作次数都是0。因此,尽管算法执行了一些步骤(如去重和排序),但实际的操作次数计算结果是0,没有进行额外的、不必要的操作次数计算。

相关问题