Skip to content

Files

Latest commit

2d4fe0d · Aug 16, 2024

History

History
337 lines (263 loc) · 11.5 KB

File metadata and controls

337 lines (263 loc) · 11.5 KB
comments difficulty edit_url rating source tags
true
困难
2241
第 126 场双周赛 Q4
数组
动态规划

English Version

题目描述

给你一个长度为 n 的整数数组 nums 和一个  整数 k 。

一个整数数组的 能量 定义为和 等于 k 的子序列的数目。

请你返回 nums 中所有子序列的 能量和 。

由于答案可能很大,请你将它对 109 + 7 取余 后返回。

 

示例 1:

输入: nums = [1,2,3], k = 3

输出: 6

解释:

总共有 5 个能量不为 0 的子序列:

  • 子序列 [1,2,3] 有 2 个和为 3 的子序列:[1,2,3][1,2,3] 。
  • 子序列 [1,2,3] 有 1 个和为 3 的子序列:[1,2,3] 。
  • 子序列 [1,2,3] 有 1 个和为 3 的子序列:[1,2,3] 。
  • 子序列 [1,2,3] 有 1 个和为 3 的子序列:[1,2,3] 。
  • 子序列 [1,2,3] 有 1 个和为 3 的子序列:[1,2,3] 。

所以答案为 2 + 1 + 1 + 1 + 1 = 6 。

示例 2:

输入: nums = [2,3,3], k = 5

输出: 4

解释:

总共有 3 个能量不为 0 的子序列:

  • 子序列 [2,3,3] 有 2 个子序列和为 5 :[2,3,3] 和 [2,3,3] 。
  • 子序列 [2,3,3] 有 1 个子序列和为 5 :[2,3,3] 。
  • 子序列 [2,3,3] 有 1 个子序列和为 5 :[2,3,3] 。

所以答案为 2 + 1 + 1 = 4 。

示例 3:

输入: nums = [1,2,3], k = 7

输出: 0

解释:不存在和为 7 的子序列,所以 nums 的能量和为 0 。

 

提示:

  • 1 <= n <= 100
  • 1 <= nums[i] <= 104
  • 1 <= k <= 100

解法

方法一:动态规划

题目需要我们在给定数组 nums 中找到所有子序列 S ,然后计算每个 S 的每个子序列 T 的和等于 k 的方案数。

我们定义 f [ i ] [ j ] 表示前 i 个数构成的若干个子序列中,每个子序列的子序列和等于 j 的方案数。初始时 f [ 0 ] [ 0 ] = 1 ,其余位置均为 0

对于第 i 个数 x ,有以下三种情况:

  1. 不在子序列 S 中,此时 f [ i ] [ j ] = f [ i 1 ] [ j ]
  2. 在子序列 S ,但不在子序列 T 中,此时 f [ i ] [ j ] = f [ i 1 ] [ j ]
  3. 在子序列 S ,且在子序列 T 中,此时 f [ i ] [ j ] = f [ i 1 ] [ j x ]

综上,状态转移方程为:

f [ i ] [ j ] = f [ i 1 ] [ j ] × 2 + f [ i 1 ] [ j x ]

最终答案为 f [ n ] [ k ]

时间复杂度 O ( n × k ) ,空间复杂度 O ( n × k ) 。其中 n 为数组 nums 的长度,而 k 为给定的正整数。

Python3

class Solution:
    def sumOfPower(self, nums: List[int], k: int) -> int:
        mod = 10**9 + 7
        n = len(nums)
        f = [[0] * (k + 1) for _ in range(n + 1)]
        f[0][0] = 1
        for i, x in enumerate(nums, 1):
            for j in range(k + 1):
                f[i][j] = f[i - 1][j] * 2 % mod
                if j >= x:
                    f[i][j] = (f[i][j] + f[i - 1][j - x]) % mod
        return f[n][k]

Java

class Solution {
    public int sumOfPower(int[] nums, int k) {
        final int mod = (int) 1e9 + 7;
        int n = nums.length;
        int[][] f = new int[n + 1][k + 1];
        f[0][0] = 1;
        for (int i = 1; i <= n; ++i) {
            for (int j = 0; j <= k; ++j) {
                f[i][j] = (f[i - 1][j] * 2) % mod;
                if (j >= nums[i - 1]) {
                    f[i][j] = (f[i][j] + f[i - 1][j - nums[i - 1]]) % mod;
                }
            }
        }
        return f[n][k];
    }
}

C++

class Solution {
public:
    int sumOfPower(vector<int>& nums, int k) {
        const int mod = 1e9 + 7;
        int n = nums.size();
        int f[n + 1][k + 1];
        memset(f, 0, sizeof(f));
        f[0][0] = 1;
        for (int i = 1; i <= n; ++i) {
            for (int j = 0; j <= k; ++j) {
                f[i][j] = (f[i - 1][j] * 2) % mod;
                if (j >= nums[i - 1]) {
                    f[i][j] = (f[i][j] + f[i - 1][j - nums[i - 1]]) % mod;
                }
            }
        }
        return f[n][k];
    }
};

Go

func sumOfPower(nums []int, k int) int {
	const mod int = 1e9 + 7
	n := len(nums)
	f := make([][]int, n+1)
	for i := range f {
		f[i] = make([]int, k+1)
	}
	f[0][0] = 1
	for i := 1; i <= n; i++ {
		for j := 0; j <= k; j++ {
			f[i][j] = (f[i-1][j] * 2) % mod
			if j >= nums[i-1] {
				f[i][j] = (f[i][j] + f[i-1][j-nums[i-1]]) % mod
			}
		}
	}
	return f[n][k]
}

TypeScript

function sumOfPower(nums: number[], k: number): number {
    const mod = 10 ** 9 + 7;
    const n = nums.length;
    const f: number[][] = Array.from({ length: n + 1 }, () => Array(k + 1).fill(0));
    f[0][0] = 1;
    for (let i = 1; i <= n; ++i) {
        for (let j = 0; j <= k; ++j) {
            f[i][j] = (f[i - 1][j] * 2) % mod;
            if (j >= nums[i - 1]) {
                f[i][j] = (f[i][j] + f[i - 1][j - nums[i - 1]]) % mod;
            }
        }
    }
    return f[n][k];
}

方法二:动态规划(优化)

方法一中的状态转移方程中,$f[i][j]$ 的值只与 f [ i 1 ] [ j ] f [ i 1 ] [ j x ] 有关,因此我们可以优化第一维空间,从而将空间复杂度优化为 O ( k )

时间复杂度 O ( n × k ) ,空间复杂度 O ( k ) 。其中 n 为数组 nums 的长度,而 k 为给定的正整数。

Python3

class Solution:
    def sumOfPower(self, nums: List[int], k: int) -> int:
        mod = 10**9 + 7
        f = [1] + [0] * k
        for x in nums:
            for j in range(k, -1, -1):
                f[j] = (f[j] * 2 + (0 if j < x else f[j - x])) % mod
        return f[k]

Java

class Solution {
    public int sumOfPower(int[] nums, int k) {
        final int mod = (int) 1e9 + 7;
        int[] f = new int[k + 1];
        f[0] = 1;
        for (int x : nums) {
            for (int j = k; j >= 0; --j) {
                f[j] = (f[j] * 2 % mod + (j >= x ? f[j - x] : 0)) % mod;
            }
        }
        return f[k];
    }
}

C++

class Solution {
public:
    int sumOfPower(vector<int>& nums, int k) {
        const int mod = 1e9 + 7;
        int f[k + 1];
        memset(f, 0, sizeof(f));
        f[0] = 1;
        for (int x : nums) {
            for (int j = k; j >= 0; --j) {
                f[j] = (f[j] * 2 % mod + (j >= x ? f[j - x] : 0)) % mod;
            }
        }
        return f[k];
    }
};

Go

func sumOfPower(nums []int, k int) int {
	const mod int = 1e9 + 7
	f := make([]int, k+1)
	f[0] = 1
	for _, x := range nums {
		for j := k; j >= 0; j-- {
			f[j] = f[j] * 2 % mod
			if j >= x {
				f[j] = (f[j] + f[j-x]) % mod
			}
		}
	}
	return f[k]
}

TypeScript

function sumOfPower(nums: number[], k: number): number {
    const mod = 10 ** 9 + 7;
    const f: number[] = Array(k + 1).fill(0);
    f[0] = 1;
    for (const x of nums) {
        for (let j = k; ~j; --j) {
            f[j] = (f[j] * 2) % mod;
            if (j >= x) {
                f[j] = (f[j] + f[j - x]) % mod;
            }
        }
    }
    return f[k];
}