[LeetCode] K Inverse Pairs Array K个翻转对数组

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 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].

这道题给了我们1到n总共n个数字,让我们任意排列数组的顺序,使其刚好存在k个翻转对,所谓的翻转对,就是位置在前面的数字值大,而且题目中表明了结果会很大很大,要我们对一个很大的数字取余。对于这种结果巨大的题目,劝君放弃暴力破解或者是无脑递归,想都不用想,那么最先应该考虑的就是DP的解法了。我们需要一个二维的DP数组,其中dp[i][j]表示1到i的数字中有j个翻转对的排列总数,那么我们要求的就是dp[n][k]了,即1到n的数字中有k个翻转对的排列总数。现在难点就是要求递推公式了。我们想如果我们已经知道dp[n][k]了,怎么求dp[n+1][k],先来看dp[n+1][k]的含义,是1到n+1点数字中有k个翻转对的个数,那么实际上在1到n的数字中的某个位置加上了n+1这个数,为了简单起见,我们先让n=4,那么实际上相当于要在某个位置加上5,那么加5的位置就有如下几种情况:

xxxx5

xxx5x

xx5xx

x5xxx

5xxxx

这里xxxx表示1到4的任意排列,那么第一种情况xxxx5不会增加任何新的翻转对,因为xxxx中没有比5大的数字,而 xxx5x会新增加1个翻转对,xx5xx,x5xxx,5xxxx分别会增加2,3,4个翻转对。那么xxxx5就相当于dp[n][k],即dp[4][k],那么依次往前类推,就是dp[n][k-1], dp[n][k-2]...dp[n][k-n],这样我们就可以得出dp[n+1][k]的求法了:

dp[n+1][k] = dp[n][k] + dp[n][k-1] + ... + dp[n][k - n]

那么dp[n][k]的求法也就一目了然了:

dp[n][k] = dp[n - 1][k] + dp[n - 1][k-1] + ... + dp[n - 1][k - n + 1]

那么我们就可以写出代码如下了:

解法一:

class Solution {
public:
    int kInversePairs(int n, int k) {
        int M = 1000000007;
        vector<vector<int>> dp(n + 1, vector<int>(k + 1, 0));
        dp[0][0] = 1;
        for (int i = 0; i <= n; ++i) {
            for (int j = 0; j < i; ++j) {
                for (int m = 0; m <= k; ++m) {
                    if (m - j >= 0 && m - j <= k) {
                        dp[i][m] = (dp[i][m] + dp[i - 1][m - j]) % M;
                    }
                }
            }
        }
        return dp[n][k];
    }
};

我们可以对上面的解法进行时间上的优化,还是来看我们的递推公式: 

dp[n][k] = dp[n - 1][k] + dp[n - 1][k-1] + ... + dp[n - 1][k - n + 1]

我们可以用k+1代替k,得到:

dp[n][k+1] = dp[n - 1][k+1] + dp[n - 1][k] + ... + dp[n - 1][k + 1 - n + 1]

用第二个等式减去第一个等式可以得到:

dp[n][k+1] = dp[n][k] + dp[n - 1][k+1] - dp[n - 1][k - n + 1]

将k+1换回成k,可以得到:

dp[n][k] = dp[n][k-1] + dp[n - 1][k] - dp[n - 1][k - n]

我们可以发现当k>=n的时候,最后一项的数组坐标才能为非负数,从而最后一项才有值,所以我们再更新的时候只需要判断一下k和n的关系,如果k>=n的话,就要减去最后一项,这种递推式算起来更高效,减少了一个循环,参见代码如下:

解法二:

class Solution {

public:
    int kInversePairs(int n, int k) {
        int M = 1000000007;
        vector<vector<int>> dp(n + 1, vector<int>(k + 1, 0));
        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 - 1][j] + dp[i][j - 1]) % M;
                if (j >= i) {
                    dp[i][j] = (dp[i][j] - dp[i - 1][j - i] + M) % M;
                }
            }
        }
        return dp[n][k];
    }
};

参考资料:

https://discuss.leetcode.com/topic/93815/java-dp-o-nk-solution/2

https://discuss.leetcode.com/topic/93765/shared-my-c-o-n-k-solution-with-explanation

本文转自博客园Grandyang的博客,原文链接:[LeetCode] K Inverse Pairs Array K个翻转对数组

,如需转载请自行联系原博主。

时间: 2024-09-17 23:03:42

[LeetCode] K Inverse Pairs Array K个翻转对数组的相关文章

[LeetCode] Subarray Product Less Than K 子数组乘积小于K

Your are given an array of positive integers nums. Count and print the number of (contiguous) subarrays where the product of all the elements in the subarray is less than k. Example 1: Input: nums = [10, 5, 2, 6], k = 100 Output: 8 Explanation: The 8

[LeetCode] Top K Frequent Words 前K个高频词

Given a non-empty list of words, return the k most frequent elements. Your answer should be sorted by frequency from highest to lowest. If two words have the same frequency, then the word with the lower alphabetical order comes first. Example 1: Inpu

10大K站原因归纳-K站事件总结

相比大家对之前的百度K站事件印像足够深刻吧?大量的站点被K,其中涉及医疗行业.淘宝客等站点,今天我为什么要提及这两个类型的站?(首先自我介绍下:我是FA团队的SEO优化组组长).因为太典型了,我们有必要仔细进行分析,然后吸取教训,保障自己的站点不被K. OK,我们开始今天的课程-网站被K的10个原因,后面会具体讲医疗行业站和淘宝客站. 1.优化过度,这一点我想做SEO的都太熟悉了,做到这个份上的都不应该会轻易犯这种低级的错误,说到底这就是搜索引擎的霸王条款,你必须被牵着鼻子走,不然你就会被K,没

网站三天一大K 两天一小K究其原因何在

最近接到了一个客户的网站,遇到了一件让人特别郁闷的事,A5提供SEO诊断服务(http://seo.admin5.com/topic-seo.html )也有少时间了,在这期间更是给很多的客户网站做了诊断,也遇到了一些比较多的麻烦,但经过A5站长网SEO团队的共同努力之后也最终都一一顺利解决了,但这次遇到的事就有点麻烦了,特别让人匪夷所思,通过跟客户的沟通发现及A5 SEO诊断优化小组的诊断发现,该网站基本上是三天一大K,网站三天一大K,两天一小K,特别奇怪,不过所幸的是,一般被K之后第二天或是

k歌软件酷我k歌使用图文步骤

  现在,唱K是很多人纾解压力,休闲娱乐的一大方式.不少人都在问,k歌软件酷我k歌怎么使用?今天,小编就来跟大家分享k歌软件酷我k歌使用图文步骤. 方法/步骤 1:界面熟悉 酷我K歌的主界面包括了很多的常用工具,如:歌词MV.曲库.直播等: 2:排行榜 我们可以在排行榜界面找到近期最热门的歌曲,下面我们来看一下: 3:使用软件K歌 K歌是该软件特色功能了,我们可以点击界面右下角的--工具--K歌按钮 5:搜索歌曲 我们可以直接在搜索框中找我们想要的歌曲. 6:录制歌曲 找到我们需要的歌曲之后,我

ccccc-if (k==1) if (1==k) if(k=1)三者有什么区别,为什么没有if(1=k)

问题描述 if (k==1) if (1==k) if(k=1)三者有什么区别,为什么没有if(1=k) if (k==1) if (1==k) if(k=1)三者有什么区别,为什么没有if(1=k) 解决方案 k==1 1==k是一样的. k=1是赋值表达式,它也可以视作一个bool表达式,当k=0的时候是false,否则是true 1=k作为赋值表达式是不合法的. 解决方案二: 对于java来说: 楼主指定的k应该是一个int型变量,属于基本数据类型,基本数据类型在java内存的常量区,如果

[LeetCode] Map Sum Pairs 映射配对之和

Implement a MapSum class with insert, and sum methods. For the method insert, you'll be given a pair of (string, integer). The string represents the key and the integer represents the value. If the key already existed, then the original key-value pai

[LeetCode] Split Array into Consecutive Subsequences 将数组分割成连续子序列

You are given an integer array sorted in ascending order (may contain duplicates), you need to split them into several subsequences, where each subsequences consist of at least 3 consecutive integers. Return whether you can make such a split. Example

寻找最大的K个数,Top K问题的堆实现

//生成随机的不重复的测试数据 #include <iostream> #include <time.h> #include <assert.h> using namespace std; //产生[l,u]区间的随机数 int randint(int l, int u) { return l+(RAND_MAX*rand()+rand())%(u-l+1); } //1000W的int,大约4M的数据,如果放在mian内,在我的机子上好像是栈溢出了,放在全局空间就没问