[leedcode][Hard]子序列宽度之和

  • 题目难度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)

终于通过了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值