Hard
题目描述
给你一个整数数组 nums。好子序列定义为 nums 的一个子序列,其中子序列中任意两个连续元素的绝对差值恰好为 1。
返回 nums 所有可能的好子序列的和。
由于答案可能非常大,请返回对 10^9 + 7 取模的结果。
注意,长度为 1 的子序列按定义被认为是好的。
示例 1:
输入:nums = [1,2,1]
输出:14
解释:
好子序列有:[1], [2], [1], [1,2], [2,1], [1,2,1]。
这些子序列中元素的和为 14。
示例 2:
输入:nums = [3,4,5]
输出:40
解释:
好子序列有:[3], [4], [5], [3,4], [4,5], [3,4,5]。
这些子序列中元素的和为 40。
提示:
1 <= nums.length <= 10^50 <= nums[i] <= 10^5
解题思路
这道题需要计算所有好子序列的和,其中好子序列要求相邻元素差值恰好为1。
核心思路是动态规划,我们需要维护两个状态:
count[i]:以值i结尾的好子序列个数sum[i]:以值i结尾的所有好子序列的元素和
对于数组中的每个元素 x,它可以:
- 单独形成一个子序列,贡献 1 个子序列,和为
x - 接在以
x-1结尾的子序列后面,贡献count[x-1]个新子序列 - 接在以
x+1结尾的子序列后面,贡献count[x+1]个新子序列
状态转移方程:
- 新的
count[x] = count[x-1] + count[x+1] + 1 - 新的
sum[x] = sum[x-1] + sum[x+1] + x * (count[x-1] + count[x+1] + 1)
其中加1是因为 x 本身可以形成一个单元素子序列。
最后答案是所有 sum[i] 的总和。
代码实现
class Solution {
public:
int sumOfGoodSubsequences(vector<int>& nums) {
const int MOD = 1e9 + 7;
unordered_map<int, long long> count, sum;
for (int x : nums) {
long long prevCount = (count[x - 1] + count[x + 1]) % MOD;
long long prevSum = (sum[x - 1] + sum[x + 1]) % MOD;
count[x] = (prevCount + 1) % MOD;
sum[x] = (prevSum + (long long)x * (prevCount + 1)) % MOD;
}
long long result = 0;
for (auto& p : sum) {
result = (result + p.second) % MOD;
}
return result;
}
};
class Solution:
def sumOfGoodSubsequences(self, nums: List[int]) -> int:
MOD = 10**9 + 7
count = {}
sum_val = {}
for x in nums:
prev_count = (count.get(x - 1, 0) + count.get(x + 1, 0)) % MOD
prev_sum = (sum_val.get(x - 1, 0) + sum_val.get(x + 1, 0)) % MOD
count[x] = (prev_count + 1) % MOD
sum_val[x] = (prev_sum + x * (prev_count + 1)) % MOD
return sum(sum_val.values()) % MOD
public class Solution {
public int SumOfGoodSubsequences(int[] nums) {
const int MOD = 1000000007;
Dictionary<int, long> count = new Dictionary<int, long>();
Dictionary<int, long> sum = new Dictionary<int, long>();
foreach (int x in nums) {
long prevCount = (count.GetValueOrDefault(x - 1, 0) +
count.GetValueOrDefault(x + 1, 0)) % MOD;
long prevSum = (sum.GetValueOrDefault(x - 1, 0) +
sum.GetValueOrDefault(x + 1, 0)) % MOD;
count[x] = (prevCount + 1) % MOD;
sum[x] = (prevSum + (long)x * (prevCount + 1)) % MOD;
}
long result = 0;
foreach (var kvp in sum) {
result = (result + kvp.Value) % MOD;
}
return (int)result;
}
}
var sumOfGoodSubsequences = function(nums) {
const MOD = 1e9 + 7;
const count = new Map();
const sum = new Map();
for (const x of nums) {
const prevCount = ((count.get(x - 1) || 0) + (count.get(x + 1) || 0)) % MOD;
const prevSum = ((sum.get(x - 1) || 0) + (sum.get(x + 1) || 0)) % MOD;
count.set(x, (prevCount + 1) % MOD);
sum.set(x, (prevSum + x * (prevCount + 1)) % MOD);
}
let result = 0;
for (const val of sum.values()) {
result = (result + val) % MOD;
}
return result;
};
复杂度分析
| 复杂度 | 分析 |
|---|---|
| 时间复杂度 | O(n) |
| 空间复杂度 | O(k) |
其中 n 是数组长度,k 是数组中不同元素的个数(最多为 min(n, 10^5))。