leetcode
leetcode 1351 ~ 1400
三次操作后最大值与最小值的最小差

三次操作后最大值与最小值的最小差

难度:

标签:

题目描述

代码结果

运行时间: 55 ms, 内存: 26.8 MB


/*
 * 思路:
 * 1. 对数组进行排序。
 * 2. 如果数组长度小于等于4,那么最多可以改变3次使所有元素相同,最大和最小值差值为0。
 * 3. 如果数组长度大于4,通过改变最多3个元素,我们可以选择从数组两端开始最多移除3个元素,计算不同移除方式下的最大最小差值。
 * 4. 取所有移除方式中的最小差值。
 */

import java.util.Arrays;

public class MinDifferenceStream {
    public int minDifference(int[] nums) {
        if (nums.length <= 4) return 0;
        int[] sortedNums = Arrays.stream(nums).sorted().toArray();
        int n = sortedNums.length;
        return Math.min(
                Math.min(sortedNums[n - 1] - sortedNums[3], sortedNums[n - 2] - sortedNums[2]),
                Math.min(sortedNums[n - 3] - sortedNums[1], sortedNums[n - 4] - sortedNums[0])
        );
    }
}

解释

方法:

题解的核心思路是最小化数组中的最大值和最小值之间的差,通过至多改变三个元素的值。考虑到只需要关注数组中的四个最大值和四个最小值,因为数组中任何大于四个元素的改变都可以被这四个最大或最小值所覆盖。如果数组长度小于或等于4,直接返回0,因为可以将所有元素改为相同的值。如果数组很大,为了效率直接使用堆(或其他方法)来找到这四个最大和四个最小的值。然后考虑所有可能的场景:改变0个,1个,2个或3个元组中最大或最小的元素,并计算可能的最小差值。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
为什么在决定改变数组中的元素时,只考虑最大的四个和最小的四个值?改变其他位置的值会如何影响结果?
在这个问题中,目标是最小化数组中的最大值和最小值之间的差。考虑到最多只能改变三个元素,因此关注数组中的最大四个值和最小四个值是因为这些值定义了最大和最小的边界。如果改变数组中任何不在这八个值中的其他元素,不会直接影响到最大值和最小值的边界,因此不会对最终的最大值与最小值的差产生影响。换句话说,只有通过改变这些边界值,才能有效地减小最大值和最小值之间的差距。
🦆
在处理大于32个元素的数组时,为什么选择直接使用堆来找到最大和最小的四个值,而不是始终使用排序?
在处理大于32个元素的数组时,使用堆来找到最大和最小的四个值是出于效率考虑。堆操作允许以对数时间复杂度插入和删除元素,特别是使用最小堆和最大堆可以直接访问最小值和最大值。这种方法比完整排序数组更高效,因为完整排序的时间复杂度为O(n log n),而使用堆找到几个最大或最小的元素只需要O(n log k),其中k是堆的大小。在本题中,k为4,所以使用堆是一个更快的解决方案。
🦆
题解中提到的`min(mx[i] - mn[3-i] for i in range(4))`的计算过程具体是如何实现最小差值的?能否详细解释这种计算方式背后的逻辑?
这种计算方式是尝试所有可能的改变最大值和最小值的组合。具体来说,`mx[i]`表示在保留最大的第i个元素的情况下,`mn[3-i]`表示在保留最小的第(4-i)个元素的情况下。这样的组合考虑了从全部保留最大值(即i=3时,保留最大的4个元素中的最大元素,同时改变最小的一个元素)到全部保留最小值(即i=0时,改变最大的3个元素,保留最小的4个元素中的最小元素)的所有场景。通过这种方式,我们可以计算出通过改变0到3个元素所能达到的最小的最大值与最小值的差,从而找到最小差值。
🦆
在数组长度小于或等于4的情况下,题解直接返回0,这种做法是否总是正确?存在哪些特殊情况可能导致这一假设不成立?
在数组长度小于或等于4的情况下,直接返回0是正确的。因为题目允许我们改变至多三个元素的值,如果数组长度为4或更少,我们可以选择将所有元素改变为数组中任一元素的值,从而使最大值和最小值相等,差为0。不存在使这一假设不成立的特殊情况,因为无论初始数组的元素如何,我们总是有足够的操作次数来使所有元素相等。

相关问题