leetcode 891. 子序列宽度之和
题目描述
一个序列的 宽度 定义为该序列中最大元素和最小元素的差值。
给你一个整数数组 nums
,返回 nums
的所有非空 子序列 的 宽度之和 。由于答案可能非常大,请返回对 109 + 7
取余 后的结果。
子序列 定义为从一个数组里删除一些(或者不删除)元素,但不改变剩下元素的顺序得到的数组。例如,[3,6,2,7]
就是数组 [0,3,1,6,2,2,7]
的一个子序列。
示例 1:
输入:nums = [2,1,3] 输出:6 解释:子序列为 [1], [2], [3], [2,1], [2,3], [1,3], [2,1,3] 。 相应的宽度是 0, 0, 0, 1, 1, 2, 2 。 宽度之和是 6 。
示例 2:
输入:nums = [2] 输出:0
提示:
1 <= nums.length <= 105
1 <= nums[i] <= 105
题解——贪心,直观解释
思路
我们知道,一个数组有2^n-1
个非空子序列,枚举显然是不可行的。
换一个角度思考这个问题,事实上,对于每一个子序列,元素的顺序不影响结果,因为我们只要知道它的最大值和最小值就可以了。所以我们想知道,对每一个元素来说,有几个子序列以它为最大值,又有几个子序列以它为最小值?
考虑以某个元素为最小值的序列个数。如果是整个序列的最小值,显然,所有包含它的子序列都以它为最小值,数目为2^(n-1)
。那次小值呢?就是包含它,但不包含最小值的序列个数,就是2^(n-2)
,这样,我们就看出规律来了:如果某个数是数组中第k小的元素,那么以它为最小值的子序列就有2^(n-k)
个。其实也很好理解,我们从选与不选的角度考虑子序列个数,当确定以第k小的元素为最小值时,前面k-1
个都不能选,第k个必须选,剩下可选可不选的还有n-k
个,子序列自然就是2^(n-k)
个了。
同理,以第k大元素为最大值的子序列也有2^(n-k)
个。
接下来考虑如何用代码计算。直接写是不可能的,因为不可能算2^100000
,所以我们维护一个系数,从1到2^(n-1)
,每次乘二,根据上述的描述,可以推知,以第k小元素为最大值的序列数=以第k大元素为最小值的序列数=2^k,(k从0开始),所以我们从小到大遍历,每次加上(2^k)*第k小值
,减去(2^k)*第k大值
。
排序时间复杂度O(nlogn)
,计算时间复杂度O(n)
代码
1 | class Solution { |