问题描述:
给定一个整数数组 A
,考虑 A
的所有非空子序列。
对于任意序列S
,设S
的宽度是 S
的最大元素和最小元素的差。
返回A
的所有子序列的宽度之和。
由于答案可能非常大,请返回答案模 10^9+7。
示例:
输入:[2,1,3]
输出:6
解释:子序列为 [1],[2],[3],[2,1],[2,3],[1,3],[2,1,3] 。相应的宽度是 0,0,0,1,1,2,2 。这些宽度之和是 6 。
提示:
1 <= A.length <= 20000
1 <= A[i] <= 20000
问题分析:
刚一看到还以为是前几天做的贝壳校招的题目,这个是说的子序列,贝壳校招那个题目是子区间。感觉这个题目说的不太严谨,说子序列不如说是非空子集。很显然,对这个序列排序是不影响结果的。求一个数列的子集,利用二进制的方法,大家一定不会陌生,因为每个元素就两个状态吗?取或者不取。这个题目也可以是二进制的思想,具体思路如下:
(1)先对原始序列排序(排序是不影响结果的哦,这个很好理解)
(2)现在单独分析一个排序后的元素A[i]
,那么这个元素在所有子集中,有几次是被作为最大值的?又有几次是被作为最小值的?
(3)继续分析,很显然A[i]被作为最大值的次数为 2^i - 1
次(这里i
从0
开始),如何理解?0 ~ i
的所有子集共有2^(i+1)
种,又因为每一位又两种状态,所以取最后一位被选中的有 2^i
种,再减去只取这一位的1
种,所以最后只有2^i - 1
。
(4)继续分析,很显然A[i]
被作为最小的次数为 2^(n - i - 1) - 1
次(这里i
从0
开始,n
为数列的长度),倒过来分析,此时的i
为最低位。
Python3实现:
class Solution:
def sumSubseqWidths(self, A):
n, res, mod = len(A), 0, 10**9 + 7
A.sort()
pow2 = [1]
for i in range(1, n): # 先把2的次方求好
pow2.append(pow2[-1] * 2 % mod)
for i, x in enumerate(A):
res += (pow2[i] - 1) * x # x 被作为最大值得 次数 应该加上
res -= (pow2[n-1-i] - 1) * x # x 被作为最小值得 次数 应该减去
res %= mod
return res
if __name__ == '__main__':
A = [2, 1, 3]
solu = Solution()
print(solu.sumSubseqWidths(A))
声明: 总结学习,有问题可以批评指正,大神可以略过哦,。