删除元素后和的最小差值
难度:
标签:
题目描述
代码结果
运行时间: 276 ms, 内存: 48.6 MB
/*
* Problem: Given an integer array nums containing 3 * n elements,
* you can delete exactly n elements, leaving 2 * n elements.
* The remaining elements can be divided into two equal parts.
* Find the minimum absolute difference between the sums of these two parts.
*/
import java.util.*;
import java.util.stream.IntStream;
public class MinDifferenceStream {
public static int minDifference(int[] nums) {
int n = nums.length / 3;
int[] prefixSum = new int[3 * n + 1];
IntStream.range(0, 3 * n).forEach(i -> prefixSum[i + 1] = prefixSum[i] + nums[i]);
PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Collections.reverseOrder());
int[] maxFirst = new int[2 * n + 1];
IntStream.range(0, 2 * n).forEach(i -> {
maxHeap.add(nums[i]);
if (maxHeap.size() > n) maxHeap.poll();
maxFirst[i + 1] = maxFirst[i] + maxHeap.peek();
});
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
int[] minSecond = new int[2 * n + 1];
IntStream.range(0, 2 * n).map(i -> 2 * n - i - 1).forEach(i -> {
minHeap.add(nums[3 * n - 1 - i]);
if (minHeap.size() > n) minHeap.poll();
minSecond[i + 1] = minSecond[i] + minHeap.peek();
});
return IntStream.range(0, n + 1).map(i -> maxFirst[n + i] - minSecond[i]).min().orElse(Integer.MAX_VALUE);
}
public static void main(String[] args) {
int[] nums = {7, 9, 5, 8, 1, 3};
System.out.println(minDifference(nums)); // Output: 1
}
}
解释
方法:
为了求差值最小的两部分和,我们可以利用两个最小堆来维护每一种可能的前n和后n元素的和。这个解决方案首先定义一个辅助函数f,该函数使用最小堆来计算前n个元素的最大可能和。对于数组的前半部分,我们使用一个负数数组来将最小堆转换成最大堆,从而可以获得前n个元素的最大和。对于数组的后半部分,我们直接使用一个最小堆来维护后n个元素的最小和。这样,对于每个元素,我们可以快速更新堆和当前的和,如果新元素比堆顶要大。最后,通过比较所有可能的前后n元素和的组合,找到最小的差值。
时间复杂度:
O(n log n)
空间复杂度:
O(n)
代码细节讲解
🦆
为什么在计算前n个元素的最大和时,需要将元素值取负再使用最小堆?
▷🦆
在函数f中,如果新元素比堆顶元素大时进行替换,这种操作的目的是什么?
▷🦆
在计算后n个元素的最小和时,为什么选择对nums数组进行反转?
▷🦆
如何保证f函数中的b数组能够正确记录每一步的和?
▷