您的位置:首页 > 大数据 > 人工智能

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

2018-01-16 22:28 393 查看
题目

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:

The integer 
n
 is in the range [1, 1000] and 
k
 is
in the range [0, 1000].
思路

比较容易辨别出来是一道DP的题目,但是确实算是比较难的了,下面是参考网上的代码之后我的理解。定义dp
[k]表示从1到n构成的数中含有k个逆序对的个数,则我们可以推导出dp
[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
[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
[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
[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
[k+1] = dp
[k]+dp[n-1][k+1]-dp[n-1][k+1-n]。这样就可以写出代码了。

当然由于dp
[k]只和dp
[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<vector<long long>> dp(n + 1, vector<long long>(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<int>(dp
[k]);
    }
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: