LeetCode:891. Sum of Subsequence Widths - Python

问题描述:

891. 子序列宽度之和

给定一个整数数组 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次(这里i0开始),如何理解?0 ~ i 的所有子集共有2^(i+1)种,又因为每一位又两种状态,所以取最后一位被选中的有 2^i种,再减去只取这一位的1种,所以最后只有2^i - 1
(4)继续分析,很显然A[i]被作为最小的次数为 2^(n - i - 1) - 1次(这里i0开始,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))

声明: 总结学习,有问题可以批评指正,大神可以略过哦,。

你可能感兴趣的:(算法,Python,LeetCode,算法,Python,LeetCode)