子序列宽度之和
难度:
标签:
题目描述
代码结果
运行时间: 152 ms, 内存: 25.7 MB
/*
* 思路:
* 1. 首先对数组进行排序。
* 2. 计算每个元素作为最大值和最小值的贡献。
* 3. 使用快速幂计算2的幂次。
* 4. 计算所有子序列的宽度和。
* 5. 最后对结果取模10^9 + 7。
* 6. 使用Java Stream简化计算过程。
*/
import java.util.Arrays;
import java.util.stream.IntStream;
public class SolutionStream {
public int sumSubseqWidths(int[] nums) {
Arrays.sort(nums);
long MOD = 1000000007;
int n = nums.length;
long[] pow2 = new long[n];
pow2[0] = 1;
for (int i = 1; i < n; i++) {
pow2[i] = (pow2[i - 1] * 2) % MOD;
}
long result = IntStream.range(0, n).mapToLong(i -> (pow2[i] - pow2[n - 1 - i]) * nums[i] % MOD).sum() % MOD;
return (int) result;
}
}
解释
方法:
该题解首先对数组进行排序。排序后,对于排序数组中的任意两个元素x和y,如果x位于y之前,则在所有包含x和y的子序列中,x总是最小值,y总是最大值。利用这一特点,题解通过遍历排序后的数组来计算所有可能的子序列的宽度之和。具体实现中,题解使用zip函数将排序数组与其翻转后的自身进行配对,配对后的元组(x, y)中x总是小于等于y。每个配对元组对应的贡献是(x - y)乘以当前的2的幂次,这是因为数组中任一元素在子序列中出现的次数等于2的幂次(即该元素可以出现或不出现,有两种情况)。题解中用pow2变量来追踪2的幂次,每次迭代后都会更新这个值。最终结果对一个大数进行模运算,以防止溢出。
时间复杂度:
O(n log n)
空间复杂度:
O(1)
代码细节讲解
🦆
为什么在计算宽度之和时需要将数组进行排序?排序的目的是什么?
▷🦆
在算法中,`pow2`变量的作用是什么?为什么要用`pow2 * 2 % MOD`更新它?
▷🦆
算法中使用`zip(nums, reversed(nums))`的意义是什么?这样配对的元素间的关系如何影响最终的宽度和?
▷🦆
题解中提到,每个配对元组的贡献是`(x - y) * pow2`,但通常我们期望x <= y,为什么这里使用x - y而不是y - x?
▷