K 个逆序对数组
难度:
标签:
题目描述
代码结果
运行时间: 196 ms, 内存: 0.0 MB
/*
思路:
使用动态规划和Java Stream API来计算 dp 数组。与传统动态规划类似,利用前缀和来优化内部循环。
通过计算前缀和来减少时间复杂度。dp[i][j] = prefix[j] - prefix[j - i]。
初始化:dp[0][0] = 1,其他 dp[0][j] = 0(j > 0)。
我们要求的结果是 dp[n][k],结果需要对 10^9 + 7 取模。
*/
import java.util.stream.IntStream;
public class KInversePairsStream {
public int kInversePairs(int n, int k) {
int MOD = 1000000007;
int[][] dp = new int[n + 1][k + 1];
dp[0][0] = 1;
for (int i = 1; i <= n; i++) {
int[] prefix = new int[k + 1];
prefix[0] = dp[i - 1][0];
IntStream.range(1, k + 1).forEach(j -> prefix[j] = (prefix[j - 1] + dp[i - 1][j]) % MOD);
IntStream.range(0, k + 1).forEach(j -> {
dp[i][j] = prefix[j];
if (j >= i) {
dp[i][j] = (dp[i][j] - prefix[j - i] + MOD) % MOD;
}
});
}
return dp[n][k];
}
}
解释
方法:
这个题解使用动态规划来解决问题。定义状态 dp[i][j] 表示使用从 1 到 i 的整数构成长度为 i 的排列,且恰好有 j 个逆序对的不同排列个数。状态转移方程为:dp[i][j] = dp[i-1][j] + dp[i-1][j-1] + ... + dp[i-1][j-i+1],即在前 i-1 个数的排列中,再插入第 i 个数,可以产生 0 到 i-1 个新的逆序对。通过累加前 i-1 个数排列的逆序对个数来计算 dp[i][j]。最后返回 dp[n][k] 即为答案。
时间复杂度:
O(n^2k)
空间复杂度:
O(nk)
代码细节讲解
🦆
在动态规划的状态转移方程中,为什么是累加`dp[i-1][j]`到`dp[i-1][j-i+1]`的值来计算`dp[i][j]`?
▷🦆
如何理解在插入第i个数时,能产生从0到i-1个新的逆序对?
▷🦆
在代码中,累加操作为什么需要在`j >= i`时减去`dp[i-1][j-i]`?这是如何帮助维护正确的逆序对计数的?
▷🦆
题解中提到的边界条件`dp[1][0] = 1`是基于什么理论或逻辑得出的?
▷