题目:
Given two integers n
and k
, find how many different arrays consist of numbers from 1
to n
such that there are exactly k
inverse pairs.
We define an inverse pair as following: For ith
and jth
element in the array, if i
< j
and a[i]
> a[j]
then it's an inverse pair; Otherwise, it's not.
Since the answer may be very large, the answer should be modulo 109 + 7.
Example 1:
Input: n = 3, k = 0 Output: 1 Explanation: Only the array [1,2,3] which consists of numbers from 1 to 3 has exactly 0 inverse pair.
Example 2:
Input: n = 3, k = 1 Output: 2 Explanation: The array [1,3,2] and [2,1,3] have exactly 1 inverse pair.
Note:
n
is in the range [1, 1000] and k
is in the range [0, 1000].思路:
比较容易辨别出来是一道DP的题目,但是确实算是比较难的了,下面是参考网上的代码之后我的理解。定义dp[n][k]表示从1到n构成的数中含有k个逆序对的个数,则我们可以推导出dp[n][k]和dp[n - 1][i]之间的递推关系:
如果我们把n放在最后一位,则所有的k个逆序对均来自于前n - 1个数所构成的逆序对,和n无关;
如果我们把n放在倒数第二位,则有1个逆序对和n有关,有k - 1个逆序对来自前n - 1个数所构成的逆序对;
……
如果我们把n放在第一位,则有n-1个逆序对和n有关,k - (n - 1)个逆序对来自前n - 1个数所构成的逆序对。
所以:dp[n][k] = dp[n-1][k]+dp[n-1][k-1]+dp[n-1][k-2]+…+dp[n-1][k+1-n+1]+dp[n-1][k-n+1]。但问题是 k - (n - 1)有可能为负数,也就是说根据n和k的不同,上面的式子有可能从某个项之后就不合法了,我们这里先写出来占位,从而得到下面两个式子:
dp[n][k] = dp[n-1][k]+dp[n-1][k-1]+dp[n-1][k-2]+…+dp[n-1][k+1-n+1]+dp[n-1][k-n+1]
dp[n][k+1] = dp[n-1][k+1]+dp[n-1][k]+dp[n-1][k-1]+dp[n-1][k-2]+…+dp[n-1][k+1-n+1]
把上面两个式子相减可以推导出:dp[n][k+1] = dp[n][k]+dp[n-1][k+1]-dp[n-1][k+1-n]。这样就可以写出代码了。
当然由于dp[n][k]只和dp[n][x],dp[n-1][x]有关,所以该代码还可以进一步将空间复杂度从O(nk)降低到O(k)。时间复杂度是O(nk)。
代码:
class Solution {
public:
int kInversePairs(int n, int k) {
long long mod = 1000000007;
if (k < 0 || k > n * (n - 1) / 2) { // k is out of the valid range
return 0;
}
if (k == 0 || k == n * (n - 1) / 2) { // k is in the corner case
return 1;
}
vector> dp(n + 1, vector(k + 1, 0));
dp[2][0] = 1, dp[2][1] = 1; // initialization for starting point
for (int i = 3; i <= n; ++i) {
dp[i][0] = 1;
for (int j = 1; j <= min(k, i * (i - 1) / 2); ++j) {
dp[i][j] = dp[i][j - 1] + dp[i - 1][j];
if (j >= i) {
dp[i][j] -= dp[i - 1][j - i];
}
dp[i][j] = (dp[i][j] + mod) % mod;
}
}
return static_cast(dp[n][k]);
}
};