目录
动态规划
特点
- 问题的答案依赖于问题的规模,比如等差数列(2, 4, 6, 8, ..., 2n). 当前的问题n的规模,决定当前的答案是f(n) = 2n;
- 当前问题的答案可以通过之前问题的答案推导而来,比如f(n) = f(n-1) + 2。
求法
使用动态规划的前提是没有显示方程,不然直接使用显示方程f(n) = 2n就可以求出结果,我们只能得出状态转移方程。
- 建立状态转移方程,通过前面已知答案,建立状态转移方程,比如上面的f(n) = f(n-1) + 2;
- 缓存之前的结果并复用,比如之前求过f(99),那当前f(100) = f(99) + 2即可;
- 从小往大推到出最终结果。
斐波那契数列 (简单)
0, 1, 1, 2, 3, ...,
当前值是前两个值的和。
按照求法,首先得到状态转移方程:f(n) = f(n-1) + f(n-2),然后有两种方法求解。
递归方法(时间复杂度O(2^n))
def fib(n):
if n < 2: # 0, 1, 1, 2, ...
return n
else:
return fib(n-1) + fib(n-2)
if __name__ == '__main__':
print(fib(3))
动态规划(时间复杂度O(n))
即把之前的结果都缓存下来,利用之前的结果,来求当前的答案。
def fib(n):
results = list(range(n+1)) # 缓存以往结果
for i in range(n+1): # 按顺利从小到大
if i < 2:
results[i] = i # n = 0时,i也等于0; n=1, i=1
else:
results[i] = results[i-1] + results[i-2] # n=2,会先过两遍if,求得前面两个值.
return results[n]
if __name__ == '__main__':
print([fib(i) for i in range(10)])
路径问题(中等)
题目:
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
问总共有多少条不同的路径?
输入:m = 3, n = 7 输出:28
提示:
1 <= m, n <= 100
- 题目数据保证答案小于等于
2 * 109
即从f(0,0)走到f(6,8),有多少条路径?
f(0, 0) = 0
f(0,1) = 1
f(1,0) = 1
f(1,1) = f(1,0) + f(0,1) = 2
f(0,2) = f(0,1) = 1
f(1,2) = f(0,2) + f(1,1) = 1 + 2 = 3
f(2,0) = 1
f(2,1) = f(1,1) +f(2,0) = 2 + 1 = 3
....
f(m, n) = f(m-1,n) + f(m, n-1)
得出推导式是f(m, n) = f(m-1,n) + f(m, n-1),其中m, n分别是行列数,且1 <= m, n <= 100
。
c++代码:
执行用时:0 ms, 在所有 C++ 提交中击败了100.00%的用户
内存消耗:6.3 MB, 在所有 C++ 提交中击败了55.63%的用户
class Solution {
public:
int uniquePaths(int m, int n) {
vector<vector<int>> results(m, vector<int>(n, 1)); // # m行,n列 初始值为1
/*题目限定的m和n从1开始
r[1,1] = r[0,1] + r[1,0] = 1 + 1 = 2
r[1,2] = r[0,2] + r[1,1] = 1 + 2 = 3
r[1,3] = r[0,3] + r[1,2] = 1 + 3 = 4
...
r[2,1] = r[1,1] + r[2,0] = 2 + 1 = 2
...
*/
for (int i = 1; i < m; i++)
for (int j = 1; j < n; j++)
{
results[i][j] = results[i-1][j] + results[i][j-1];
}
return results[m-1][n-1];
}
};
python代码:
执行用时:12 ms, 在所有 Python 提交中击败了94.21%的用户
内存消耗:12.9 MB, 在所有 Python 提交中击败了76.84%的用户
class Solution(object):
def uniquePaths(self, m, n):
"""
:type m: int
:type n: int
:rtype: int
"""
results = [[1] * n] * m # m行,n列 初始值为1
# 题目限定的m和n从1开始
# r[1,1] = r[0,1] + r[1,0] = 1 + 1 = 2
# r[1,2] = r[0,2] + r[1,1] = 1 + 2 = 3
# r[1,3] = r[0,3] + r[1,2] = 1 + 3 = 4
# ...
# r[2,1] = r[1,1] + r[2,0] = 2 + 1 = 2
# ...
for i in range(1, m): # 一行一行的来
for j in range(1, n):
results[i][j] = results[i-1][j] + results[i][j-1]
return results[m-1][n-1]