LeetCode简易题解--629
2017-09-12 23:15
288 查看
这道题涉及到动态规划的知识。
动态规划有三个核心元素:最优子结构、边界、状态转移方程。
这道题的难点在于如何找出状态转移方程,实际上更多的是一个数学问题。
首先n=1时,输出值始终为0(显而易见);k=0时,输出值始终为1(升序排列);这是边界。
记输出为F(n, k)。
如何推导出状态转移方程呢?首先看看n从4变成5发生了什么:
因为5肯定是最大的数,所以(以下X X X X是同一序列):
5 X X X X 产生了4个新的inverse pairs
X 5 X X X 产生了3个新的inverse pairs
X X 5 X X 产生了2个新的inverse pairs
X X X 5 X 产生了1个新的inverse pairs
X X X X 5 产生了0个新的inverse pairs
可以看到,当n增加1时,k的值增加的范围为[0, n]。因此,F(n+1, k)的值由以下几个值的和得到:
F(n, k) 当n+1放在序列末尾
F(n, k-1) 当n+1放在倒数第二个
F(n, k-2) 当n+1放在倒数第三个
…
F(n, k-n+1) 当n+1放在序列头部
因此状态转移方程为:
F(n, k) = F(n-1, k) + F(n-1, k-1) + … + F(n-1, k-n+1)
根据以上方程构建表格即可求出答案。
但是以上方法的时间复杂度为O(n * k ^ 2),有没有更好的方法呢?
当然。
再看以上的状态转移方程,将其表示为:
假设i = 5:
可以看出,当 j < i 时,
当 j >= i 时:
同样地,可以得到
因此,当 j >= i 时,
此方法的时间复杂度为O(n * l)。
最后,代码为:
另外,要注意对计算值取模。第10行括号内取模是为了避免减法得到负数。
动态规划有三个核心元素:最优子结构、边界、状态转移方程。
这道题的难点在于如何找出状态转移方程,实际上更多的是一个数学问题。
首先n=1时,输出值始终为0(显而易见);k=0时,输出值始终为1(升序排列);这是边界。
记输出为F(n, k)。
如何推导出状态转移方程呢?首先看看n从4变成5发生了什么:
因为5肯定是最大的数,所以(以下X X X X是同一序列):
5 X X X X 产生了4个新的inverse pairs
X 5 X X X 产生了3个新的inverse pairs
X X 5 X X 产生了2个新的inverse pairs
X X X 5 X 产生了1个新的inverse pairs
X X X X 5 产生了0个新的inverse pairs
可以看到,当n增加1时,k的值增加的范围为[0, n]。因此,F(n+1, k)的值由以下几个值的和得到:
F(n, k) 当n+1放在序列末尾
F(n, k-1) 当n+1放在倒数第二个
F(n, k-2) 当n+1放在倒数第三个
…
F(n, k-n+1) 当n+1放在序列头部
因此状态转移方程为:
F(n, k) = F(n-1, k) + F(n-1, k-1) + … + F(n-1, k-n+1)
根据以上方程构建表格即可求出答案。
但是以上方法的时间复杂度为O(n * k ^ 2),有没有更好的方法呢?
当然。
再看以上的状态转移方程,将其表示为:
dp[i][j] = dp[i-1][j] + dp[i-1][j-1] + dp[i-1][j-2] + ..... +dp[i-1][j - i + 1]
假设i = 5:
dp[i][0] = dp[i-1][0] (creates 0 inverse pair) dp[i][1] = dp[i-1][0] (1) + dp[i-1][1] (0) = dp[i][0] + dp[i-1][1] dp[i][2] = dp[i-1][0] (2) + dp[i-1][1] (1) + dp[i-1][2] (0) = dp[i][1] + dp[i-1][2] . . . dp[i][4] = dp[i-1][0] (4) + dp[i-1][1] (3) + dp[i-1][2] (2) + dp[i-1][3] (1) + dp[i-1][4] (0) = dp[i][3] + dp[i-1][4]
可以看出,当 j < i 时,
dp[i][j] = dp[i][j-1] +dp[i-1][j]
当 j >= i 时:
dp[i][5] = dp[i-1][1] + dp[i-1][2] + dp[i-1][3] + dp[i-1][4] + dp[i-1][5] = dp[i-1][0] + dp[i-1][1] + dp[i-1][2] + dp[i-1][3] + dp[i-1][4] + dp[i-1][5] - dp[i-1][0] = dp[i][4] + dp[i-1][5] - dp[i-1][0] = dp[i][5] - dp[i-1][0]
同样地,可以得到
dp[i][6] = dp[i][5] + dp[i-1][6] - dp[i-1][1] = dp[i][6] - dp[i-1][1]
因此,当 j >= i 时,
dp[i][j] = dp[i][j] - dp[i-1][j-i]
此方法的时间复杂度为O(n * l)。
最后,代码为:
int kInversePairs(int n, int k) { int mod = pow(10, 9) + 7; vector<vector<int> > dp(n + 1, vector<int>(k + 1)); 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][j - 1] + dp[i - 1][j]) % mod; if(j - i >= 0) dp[i][j] = (dp[i][j] - dp[i - 1][j - i] + mod) % mod; } } return dp [k]; }
另外,要注意对计算值取模。第10行括号内取模是为了避免减法得到负数。
相关文章推荐
- LeetCode简易题解--105、106
- LeetCode简易题解--091
- LeetCode简易题解--120
- LeetCode简易题解--103
- LeetCode简易题解--098、099
- LeetCode简易题解--375
- LeetCode简易题解--221
- LeetCode简易题解--039
- LeetCode简易题解--053
- LeetCode简易题解--121、122、123、188
- LeetCode简易题解--084,085
- leetcode题解-86. Partition List
- leetcode题解-336. Palindrome Pairs
- Leetcode题解-24. Swap Nodes in Pairs
- leetcode 题解代码整理 21-25题
- LeetCode题解——Linked List Cycle II
- Leetcode:minimum_depth_of_binary_tree题解
- LeetCode题解第二章线性表2.1.1~2.1.2
- Leetcode题解 - 215. Kth Largest Element in an Array
- LightOJ数论题单及简易题解