给出两个整数 n 和 k,找出所有包含从 1 到 n 的数字,且恰好拥有 k 个逆序对的不同的数组的个数。
逆序对的定义如下:对于数组的第i个和第 j个元素,如果满i < j且 a[i] > a[j],则其为一个逆序对;否则不是。
由于答案可能很大,只需要返回 答案 mod 109 + 7 的值。
示例 1:
输入: n = 3, k = 0
输出: 1
解释:
只有数组 [1,2,3] 包含了从1到3的整数并且正好拥有 0 个逆序对。
n 的范围是 [1, 1000] 并且 k 的范围是 [0, 1000]。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/k-inverse-pairs-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
看数据范围
要用O(n*k)的方法,即样本对应模型
dp[i][j]的含义:
当我用12,3…n直到这些数字玩排列的情况下,正好逆序对数量有j个的排列有几个
第一列为0个逆序对,全填1
我们举出具体例子
dp[5][3]: 1,2,3,4.5这些数字去排列,降序对的数量是3个的排列有几个?
根据样本对应模型往往可能性的划分和结尾有关
看这个5怎么摆放
假设1,2,3,4 这4个数形成排列的逆序对数的排列我知道,即dp[4][3]
1)5放在最后面:dp[4][3]
2)5放在倒数第二位,形成1个逆序对,前4个数字只要凑出2个逆序对就行了:dp[4][2]
3)5放在倒数第三位,形成2个逆序对,前四个数字只要凑出1个逆序对就行了:dp[4][1]
4)5放在倒数第四位,dp[4][0];
根据上面可知,dp[5][3]=dp[4][3]+dp[4][2]+dp[4][1]+dp[4][0]
即dp[i][j]=dp[i-1][j]+…+dp[i-1][0];
我们可以推出dp[5][4]=dp[4][4]+…dp[4][0]=dp[5][3]+dp[4][4]
即dp[i][j]=dp[i][j - 1] + dp[i - 1][j]
当j>=i的情况会有不同
我们可以知道
dp[5][7]=dp[4][7…3]
dp[5][8]=dp[4][8…4]
即dp[5][8]=dp[4][8]+dp[5][7]-dp[4][3]
即dp[i][j] = dp[i][j - 1] + dp[i - 1][j]- dp[i - 1][j - i]
class Solution {
public int kInversePairs(int n, int k) {
if (n < 1 || k < 0) {
return 0;
}
int[][] dp=new int[n+1][k+1];
int mod = 1000000007;
dp[0][0]=1;
for(int i=1;i<=n;i++){
dp[i][0]=1;
for(int j=1;j<=k;j++){
dp[i][j]=(dp[i][j-1]+dp[i-1][j])%mod;
if(j>=i){
dp[i][j]=(dp[i][j]-dp[i-1][j-i]+mod)%mod;
}
}
}
return dp[n][k];
}
}