子序列宽度之和【LC891】
一个序列的 宽度 定义为该序列中最大元素和最小元素的差值。
给你一个整数数组
nums
,返回nums
的所有非空 子序列 的 宽度之和 。由于答案可能非常大,请返回对109 + 7
取余 后的结果。子序列 定义为从一个数组里删除一些(或者不删除)元素,但不改变剩下元素的顺序得到的数组。例如,
[3,6,2,7]
就是数组[0,3,1,6,2,2,7]
的一个子序列。
The width of a sequence is the difference between the maximum and minimum elements in the sequence.
Given an array of integers
nums
, return the sum of the widths of all the non-empty subsequences ofnums
. Since the answer may be very large, return it modulo109 + 7
.A subsequence is a sequence that can be derived from an array by deleting some or no elements without changing the order of the remaining elements. For example,
[3,6,2,7]
is a subsequence of the array[0,3,1,6,2,2,7]
.
没想出来,题解feat三叶姐
-
思路:
-
对于某个子序列而言,若其最大值为a,最小值为b,那么该子序列对答案res的贡献是(a-b)
-
因此统计每个nums[i]作为最值时,有多少个子序列,统计其对答案的贡献就得到了最终答案
当nums[i]为最小值时,假设nums中有k个大于nums[i]的数,根据组合数原理,那么子序列个数为 2 k 2^k 2k;
- 其作为最小值是对res的贡献为 2 k ∗ n u m s [ i ] 2^k * nums[i] 2k∗nums[i]
当nums[i]为最大值时,假设nums中有k个小于nums[i]的数,根据组合数原理,那么子序列个数为 2 k 2^k 2k
- 其作为最大值是对res的贡献为 2 k ∗ ( − n u m s [ i ] ) 2^k * (-nums[i]) 2k∗(−nums[i])
-
如何快速计算比nums[i]大或者小的个数
- 将nums排序后,大于nums[i]的个数为n-i-1,小于nums[i]的个数为i
-
nums[i]中的重复元素是否会对结果产生影响?
- 不会,无论是将 nums[i]视作最大值还是最小值,我们的组合数均取决于某一侧的数的个数,因此不会答案正确性产生影响。
-
-
实现:
-
为了避免重复计算 2 k 2^k 2k,通过打表的方式进行预处理
class Solution { static int MOD = (int)1e9 + 7; public int sumSubseqWidths(int[] nums) { long ans = 0; int n = nums.length; long[] p = new long[n+1]; p[0] = 1; for (int i = 1; i <= n; i++){ p[i] = p[i-1] * 2 % MOD; } Arrays.sort(nums); for (int i = 0; i < n; i++){ ans += (p[i] * nums[i]) % MOD; ans %= MOD; ans -= (p[n - i - 1] * nums[i]) % MOD; ans %= MOD; } return (int)ans; } }
-
复杂度
- 时间复杂度: O ( n l o g n ) O(n log n) O(nlogn)
- 空间复杂度: O ( l o g n ) O(logn) O(logn)
-