数组中k个逆序对问题

179 阅读1分钟

「这是我参与2022首次更文挑战的第15天,活动详情查看:2022首次更文挑战」。

n个数里面,形成k个逆序对(降序对)的有几个,求逆序对有多少种排列

LeetCode

一、分析

dp[i][j]:有i个数,所有排列的情况下,有j个逆序对(降序对)

n = 3,k = 2

1,2,3

1,2,3 1到2,1到3,2到3,0个逆序对(降序对)

1,3,2 1到3,1到2,3到2,1个逆序对(降序对)

2,1,3 2到1,2到3,1到3,1个逆序对(降序对)

2,3,1 2到3,2到13到12个逆序对 (降序对)√

3,1,2 3到13到2,1到2,2个逆序对 (降序对)√

3,2,1 3到23到12到1,3个逆序对(降序对)

n行k列,推出第一列全是1,第一行从第二列开始全是0

例如dp[5][3]:(12345)5个数,3个降序对

有如下情况:

  • dp[4][3]:(1234),3个降序对,5在最右边abcd5
  • dp[4][2]:(1234),2个降序对,5在倒数第二位置abc5d(5到d
  • dp[4][1]:(1234),1个降序对,5在倒数第三位置ab5cd(5到c,5到d
  • dp[4][0]:(1234),0个降序对,5在倒数第二位置a5bcd(5到b,5到c,5到d

斜率优化:

dp[5][3] = dp[4][3210]

dp[5][4] = dp[4][43210] = dp[4][4] + dp[5][3]

推出 j<i:dp[i][j] = dp[i-1][j] + dp[i][j-1]

dp[5][7] = dp[4][7...3]

dp[5][8] = dp[4][8...4] = dp[4][8] + dp[5][7] - dp[4][3]

推出 j≥i:dp[i][j] = dp[i-1][j] + dp[i][j-1] - dp[i-1][j-i]

二、实现

public static int kInversePairs(int n, int k) {
    if (n < 1 || k < 0) {
        return 0;
    }
    int[][] dp = new int[n + 1][k + 1];
    dp[0][0] = 1;
    int mod = 1000000007;
    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];
}

三、总结

样本对应模型,往往答案跟结尾有关