- 题目难度Hard
给定一个整数数组 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 。
解法一:
如果类别有3个元素,则取法有000, 001, 010, 011, 100, 101, 110, 111,共8种,是2的3次方。
循环8次,把次数转化为二进制,0代表对应位置上的元素不取,1代表取。即可得出所有子列。
注:如果原列表中有重复元素,则此方法求得的子列中也有重复元素。
代码:
A = [2,1,3]
l = len(A)
pos = 2 ** l
subset = []
Sum = 0
for i in range(pos):
bin_num = str(bin(i)).replace('b','0').rjust(pos,'0')[-l:]
# print(bin_num)
x = [x for (x,y) in zip(A,bin_num) if y == '1']
Sum += max(x)-min(x) if x != [] else 0
print(Sum)
然而此方法运算超时。
解法二:
删除元素法。当前数列作为一个子列存储下来。每去掉一个元素,剩下的子列进行递归调用。为做到不重复,我们规定每一步删除元素只能在上一步删除元素的右边。
代码:
class Solution(object):
def sumSubseqWidths(self, A):
"""
:type A: List[int]
:rtype: int
"""
self.l = len(A)
self.sum = 0
if self.l == 0:
return [0]
self.fun(A[:], 0)
return self.sum
# 求子列。a为开始删除元素的位置
def fun(self, nums, a):
self.sum += max(nums)-min(nums) if nums != [] else 0
if len(nums) == 0:
return
# 从a往后,每个元素删除时,递归剩下的元素删除的方式
for i in range(a, len(nums)):
self.fun(nums[:i]+nums[i+1:], i)
s = Solution()
A = [2,1,3]
r = s.sumSubseqWidths(A)
print(r)
依然超时……我怒了。
解法三:
再仔细看题,我发现,这个题求的是子列宽度和,并不要求求子列。
给数列排序后,子列宽度取决于子列在原数列中最左端值与最右端值的差。
所以,这个问题的解 = 某区间内子列的种类数 × 此区间的宽度(ps:区间左右端点必须包含在子列内)
并且,区间内子列种类数 = 2 ** (区间长度 - 2),为减少运算,预存数组pow2 = [1, 2, 4, 8, 16...]以备调用
代码:
class Solution(object):
def sumSubseqWidths(self, A):
"""
:type A: List[int]
:rtype: int
"""
MOD = 10**9 + 7
A = sorted(A)
ans = 0
l = len(A)
fast = 1
slow = 0
pow2 = [1]
for i in range(1, l):
pow2.append(pow2[-1] * 2 % MOD)
for slow in range(l-1): # 最后一个值作为子列时宽度为0,不用计算
for fast in range(slow+1, l):
ans += pow2[fast-slow-1] * (A[fast] - A[slow])
ans %= MOD
return ans
依然超时。。。。。。跪。。。。。。
解法四:
看了答案,输给了公式推导,,额,,没想到还能公式推导!!!
代码:
class Solution(object):
def sumSubseqWidths(self, A):
"""
:type A: List[int]
:rtype: int
"""
MOD = 10**9 + 7
A = sorted(A)
ans = 0
l = len(A)
pow2 = [1]
for i in range(1, l):
pow2.append(pow2[-1] * 2 % MOD)
for i in range(l): # 最后一个值作为子列时宽度为0,不用计算
ans = (ans + (pow2[i] - pow2[l-i-1]) * A[i]) % MOD
return ans
s = Solution()
A = [2,1,3]
r = s.sumSubseqWidths(A)
print(r)
终于通过了。