LeetCode 891. Sum of Subsequence Widths
題目
一個序列的寬度指的是序列中最大值和最小值的差。
輸入整數陣列nums,求nums中所有非空子序列的寬度總和。答案很大,先模10^9+7後回傳。
解法
順序不影響答案,總之先排序。
遍歷排序好的nums,窮舉每個nums[i]作為最大值,並維護先前出現過的最小值貢獻。
以[1, 2, 3, 4]為例:
- 加入1,mn = []
- 加入2,mn = [1*20]
- 加入3,mn = [1*21 + 2*20]
- 加入4,mn = [1*31 + 2*22 + 3*20]
發現一個規律,每加入一個新的元素x,上一次的mn會先變成兩倍再加上x。
每當我們加入nums[i],這時以nums[i]為最大值的子序列會有2i個,扣除掉其本身,對最大值貢獻應是nums[i] * 2i。
維護最小值貢獻mn以及最大值貢獻次數cnt,一邊遍歷nums一邊更新答案。
瓶頸是排序,時間複雜度O(N log N)。
空間複雜度O(1)。
class Solution:
def sumSubseqWidths(self, nums: List[int]) -> int:
MOD=10**9+7
nums.sort()
ans=0
mn=0
cnt=1
for x in nums:
ans+=cnt*x-x-mn
ans%=MOD
cnt*=2
cnt%=MOD
mn=mn*2+x
mn%=MOD
return ans
官方解答和討論區幾乎都是這一種解法。
N個元素,總共會產生2^N-1個非空子序列,也就是最大值和最小值共2^N-1個。
一樣遍歷排序好的nums,當窮舉到nums[i]時,左方有i個元素都,而右方有N-1-i個元素。
左邊i個元素可以產生2^i種子序列,並以nums[i]為最大值;右邊N-1-i個元素可以產生2^(N-1-i)種子序列,並以nums[i]為最大值。
分別將最大最小值的貢獻加入答案中即可。
瓶頸是排序,時間複雜度O(N log N)。
空間複雜度O(1)。
class Solution:
def sumSubseqWidths(self, nums: List[int]) -> int:
MOD=10**9+7
N=len(nums)
nums.sort()
POW=[1]*N
for i in range(1,N):
POW[i]=(POW[i-1]*2)%MOD
ans=0
for i,x in enumerate(nums):
ans+=POW[i]*x
ans-=POW[N-1-i]*x
ans%=MOD
return ans