Kimi LeetCode 3251. 单调数组对的数目 II TypeScript实现
以下是 LeetCode 3251. 单调数组对的数目 II 的 TypeScript 实现。
核心思路
与 3250 完全相同,只是 `nums[i]` 的范围扩大到 `1000`,因此 DP 数组维度相应增大。仍采用 动态规划 + 前缀和优化:
- `dp[j]` 表示当前位置 `arr1[i] = j` 的方案数
- 转移时 `prev_j <= min(j, j + nums[i-1] - nums[i])`
- 前缀和数组将区间求和优化到 O(1)
TypeScript 代码
```typescript
function countOfPairs(nums: number[]): number {
const MOD = 1_000_000_007;
const n = nums.length;
const m = Math.max(...nums);
// dp[j] 表示当前位置,arr1[i] = j 的方案数
let dp: number[] = new Array(m + 1).fill(0);
// 初始化:i = 0 时,arr1[0] 可以是 0 到 nums[0]
for (let j = 0; j <= nums[0]; j++) {
dp[j] = 1;
}
for (let i = 1; i < n; i++) {
// 计算前缀和:prefix[j] = sum(dp[0..j])
const prefix: number[] = new Array(m + 1).fill(0);
prefix[0] = dp[0];
for (let j = 1; j <= m; j++) {
prefix[j] = (prefix[j - 1] + dp[j]) % MOD;
}
const newDp: number[] = new Array(m + 1).fill(0);
const diff = nums[i - 1] - nums[i];
for (let j = 0; j <= nums[i]; j++) {
// prev_j <= min(j, j + diff)
const limit = Math.min(j, j + diff);
if (limit >= 0) {
newDp[j] = prefix[limit];
}
// limit < 0 时,newDp[j] 保持为 0
}
dp = newDp;
}
// 答案为所有 dp[j] 之和(j 从 0 到 nums[n-1])
let ans = 0;
for (let j = 0; j <= nums[n - 1]; j++) {
ans = (ans + dp[j]) % MOD;
}
return ans;
}
```
复杂度分析
维度 复杂度
时间 O(n × m),`n <= 2000`,`m = max(nums) <= 1000`
空间 O(m),滚动数组优化
关键点
- 前缀和优化:`prefix[j] = (prefix[j-1] + dp[j]) % MOD`,将 `sum(dp[0..k])` 的计算降到 O(1)
- 负数处理:`limit = Math.min(j, j + diff)` 可能为负,此时无合法前驱,保持 0
- 滚动数组:每轮只保留上一行状态,空间复杂度 O(m)
- 取模:每次加法后取模,防止整数溢出(TypeScript 中 `number` 为双精度浮点,最大安全整数约 9×10¹⁵,本题中间结果在可控范围内,但仍建议取模)
更多推荐



所有评论(0)