[Leetcode] 629. K Inverse Pairs Array 解题报告

题目

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:

  1. The integer 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]);
    }
};

你可能感兴趣的:(IT公司面试习题)