LC 629. K Inverse Pairs Array
https://leetcode.com/problems/k-inverse-pairs-array/
首先这个问题是个动态规划问题,状态方程如下:
- dp[n][k] 表示从1-n的序列,存在k个inverse pairs的个数
- dp[n][k] = dp[n-1][k] + dp[n-1][k-1] + … dp[n-1][max(k-n+1, 0)]
考虑n=4的情况,我们如何放置数字4。假设n=3的排列是abc, 有x个inverse pairs, 看看数字4的位置会产生多个个inverse pairs
- a b c 4. x个
- a b 4 c. x+1个
- a 4 b c. x+2个
- 4 a b c. x+3个
如果简单地按照这个状态方程计算的话,时间复杂度是O(n^3).
class Solution: def kInversePairs(self, n: int, k: int) -> int: # dp[n][k] = dp[n-1][k] + dp[n-1][k-1] + ... dp[n-1][max(k-n+1, 0)] dp = [[0] * (k + 1) for _ in range(n + 1)] dp[1][0] = 1 for i in range(1, n): for j in range(0, k + 1): for off in range(0, i + 1): if (off + j) > k: break dp[i + 1][off + j] += dp[i][j] # print(dp) return dp[n][k]
如果观察上面方程的话,明显可以感觉到这是一个滑动窗口。
- dp[n][k-1] = dp[n-1][k-1] + dp[n-1][k-2] + … dp[n-1][max(k-n, 0)]
- dp[n][k] = dp[n-1][k] + dp[n-1][k-1] + … dp[n-1][max(k-n+1, 0)]
- dp[n][k] = dp[n-1][k] + dp[n][k-1] - dp[n-1][max(k-n, 0)]
这个滑动窗口计算需要非常小心,因为下标在不断地变化.
class Solution: def kInversePairs(self, n: int, k: int) -> int: # dp[n][k] = dp[n-1][k] + dp[n-1][k-1] + ... dp[n-1][max(k-n+1, 0)] # 这个状态方程需要计算优化 MOD = 10 ** 9 + 7 dp = [[0] * (k + 1) for _ in range(n + 1)] dp[1][0] = 1 for i in range(2, n + 1): acc = 0 for j in range(0, k + 1): # dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1] + ... dp[i - 1][j - i + 1] + (dp[i-1][j-i]) acc += dp[i - 1][j] if j >= i: acc -= dp[i - 1][j - i] acc = acc % MOD dp[i][j] = (acc + dp[i][j]) % MOD # print(dp) return dp[n][k]