LeetCode 629. K个逆序对数组

Posted zaq19970105

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode 629. K个逆序对数组相关的知识,希望对你有一定的参考价值。

题目链接:https://leetcode-cn.com/problems/k-inverse-pairs-array/

题目大意

  略。

分析

  首先,1~n 这 n 个数所能产生的最大逆序对为 n * (n - 1) / 2 对。
  设 dp[i][j] 表示 1~i 能产生 j 对逆序对的排列种数。
  这里定义一下如果下标为负数,这一项为 0。
  在考虑接下来一个事实:对于序列 1,2,3,4,5 和 2,5,7,9,10,在这个问题下,我可以说这两个序列是等价的,因为产生逆序对的本质是大小关系而不是数实际的大小。
  现在考虑状态转移方程。
  首先当 j > i * (i - 1) / 2 时,dp[i][j] = 0。
  其次当 j = 0 时,dp[i][0] = 1,只有顺着排一种方法。
  以上确定了初始状态。
  对于其他 dp[i][j],我们如果考虑在队头放第 k 大的数,那么这个数就贡献了 k - 1 对逆序对,剩下的 i - 1 个不同的数就可以转化为子问题,也就是 dp[i - 1][j - k]。
  同理我们也可以在队头放其他数,分别求一下贡献,就能得到状态转移方程:$$dp[i][j] = \sum_k = max(0, j - i + 1)^j dp[i - 1][k]$$
  仔细观察前后两项的关系可以发现:$$dp[i][j] = dp[i][j - 1] + dp[i - 1][j] - dp[i - 1][max(0, j - i + 1) - 1]$$
  不过不推这个式子也能做,搞个前缀和即可。

代码如下

技术图片
 1 class Solution 
 2     int dp[2][1007], mod = 1e9 + 7, now = 0;
 3 public:
 4     int kInversePairs(int n, int k) 
 5         dp[now][0] = 1;
 6         
 7         for(int i = 1; i <= n; ++i) 
 8             now = !now;
 9             dp[now][0] = 1;
10             for(int j = 1; j <= k; ++j) 
11                 if(2 * j > i * (i - 1)) break;
12                 dp[now][j] = (dp[now][j - 1] + dp[!now][j]) % mod;
13                 if(j - i >= 0) dp[now][j] = (dp[now][j] - dp[!now][j - i] + mod) % mod;
14             
15         
16         
17         return dp[now][k];
18     
19 ;
View Code

 

以上是关于LeetCode 629. K个逆序对数组的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode 495. 提莫攻击 / 629. K个逆序对数组(动规,不会) / 375. 猜数字大小 II(区间dp)

2021-11-11 光棍节快乐

2021-06-01:K个逆序对数组。给出两个整数 n 和 k,找出所有包含从 1 到 n 的数字,且恰好拥有 k 个逆序对的不同的数组的个数。逆序对的定义如下:对于数组的第i个和第 j个元素,如果满

LeetCode692. 前K个高频单词 / 剑指 Offer 50. 第一个只出现一次的字符 / 剑指 Offer 51. 数组中的逆序对 / 2. 两数相加

数据结构与算法之深入解析“K个逆序对数组”的求解思路与算法示例

LeetCode-数组数组中的逆序对