629.K个逆序对数组

90 阅读1分钟

题目:
给出两个整数 n 和 k,找出所有包含从 1 到 n 的数字,且恰好拥有 k 个逆序对的不同的数组的个数。

逆序对的定义如下:对于数组的第i个和第 j个元素,如果满i < j且 a[i] > a[j],则其为一个逆序对;否则不是。

由于答案可能很大,只需要返回 答案 mod 109 + 7 的值。
算法:
本题考查动态规划。 状态转移方程:
【f(n)(k)需要k个逆序对,由第n个往f(n-1)的不同位置插入的到k个逆序对。n和前n-1个数最多构造n-1个逆序对,所以f(n - 1)最少要能提供k-(n-1))个逆序对,即f(n-1)(k - (n - 1))】
f(n)(k) = f(n-1)(k) + f(n-1)(k - 1) + f(n-1)(k - 2) + f(n-1)(k - (n - 1))
f(n)(k - 1) = f(n-1)(k -1) + f(n-1)(k - 2) + f(n-1)(k - 3) + f(n-1)(k - 1 - (n - 1)) 得到:
f(n)(k)
= f(n)(k - 1) + f(n-1)(k) - f(n-1)(k - 1 - (n - 1))
= f(n)(k - 1) + f(n-1)(k) - f(n-1)(k - n)
参考: leetcode.cn/problems/k-…

func kInversePairs(n int, k int) int {
	MOD := 1000000007
	dp := make([][]int, n + 1)
	for i := range dp {
		dp[i] = make([]int, k + 1)
	}
	dp[1][0] = 1
	// i是n的
	for i := 2; i <= n; i ++ {
		maxParis := min(k, (i - 1) * i / 2)
		// j 是逆序对的数量
		for j := 0; j <= maxParis; j ++ {
				tmp1, tmp2 := 0, 0
				if j - 1 >= 0 {
					tmp1 = dp[i][j - 1]
				}
				if j - i >= 0 {
					tmp2 = dp[i - 1][j - i]
				}
				dp[i][j] = (tmp1 + dp[i - 1][j] - tmp2 + MOD) % MOD
	
			// }
			
		}
	}

	return dp[n][k]
}

func max(i , j int) int {
	if i > j {
		return i
	}
	return j
}

func min(i , j int) int {
	if i < j {
		return i
	}
	return j
}