将数组分成两个数组并最小化数组和的差
难度:
标签:
题目描述
给你一个长度为 2 * n
的整数数组。你需要将 nums
分成 两个 长度为 n
的数组,分别求出两个数组的和,并 最小化 两个数组和之 差的绝对值 。nums
中每个元素都需要放入两个数组之一。
请你返回 最小 的数组和之差。
示例 1:
输入:nums = [3,9,7,3] 输出:2 解释:最优分组方案是分成 [3,9] 和 [7,3] 。 数组和之差的绝对值为 abs((3 + 9) - (7 + 3)) = 2 。
示例 2:
输入:nums = [-36,36] 输出:72 解释:最优分组方案是分成 [-36] 和 [36] 。 数组和之差的绝对值为 abs((-36) - (36)) = 72 。
示例 3:
输入:nums = [2,-1,0,4,-2,-9] 输出:0 解释:最优分组方案是分成 [2,4,-9] 和 [-1,0,-2] 。 数组和之差的绝对值为 abs((2 + 4 + -9) - (-1 + 0 + -2)) = 0 。
提示:
1 <= n <= 15
nums.length == 2 * n
-107 <= nums[i] <= 107
代码结果
运行时间: 1060 ms, 内存: 0.0 MB
// Java Stream solution
// 思路: 使用Java Stream的组合生成器来生成所有可能的分组. 由于Stream的特性, 我们可以简化生成组合和计算最小差值的过程.
import java.util.Arrays;
import java.util.stream.IntStream;
public class SolutionStream {
public int minimumDifference(int[] nums) {
int n = nums.length / 2;
int totalSum = Arrays.stream(nums).sum();
return IntStream.range(0, 1 << (2 * n))
.filter(mask -> Integer.bitCount(mask) == n)
.map(mask -> {
int sum = 0;
for (int i = 0; i < 2 * n; i++) {
if ((mask & (1 << i)) != 0) {
sum += nums[i];
}
}
return Math.abs(totalSum - 2 * sum);
})
.min()
.orElse(0);
}
}
解释
方法:
这个题解的思路是将数组分成左右两部分,分别求出左右两部分所有可能的子集和。然后对于左边每一个可能的子集和,在右边部分通过二分查找找到最接近总和一半的子集和,两者相加即可得到最接近总和一半的一种划分方式。所有划分方式中的最小值即为答案。
时间复杂度:
O(n*2^n)
空间复杂度:
O(2^n)
代码细节讲解
🦆
在算法中,为什么选择将原数组平分为两部分来计算子集和,而不是其他划分方式?
▷🦆
题解中提到使用默认字典来存储子集和,这种数据结构相比普通字典有什么优势?
▷🦆
为什么在处理子集和时需要对每个集合的元素数量进行限制?
▷🦆
二分查找在题解中的应用是如何确保可以找到最接近总和一半的子集和的?
▷