[TOC]
void recursion(int level, int param) {
// recursion terminator
if (level > MAX_LEVEL) {
// process result
return ;
}
// process current logic
process(level, param);
// drill down
recursion(level + 1, param);
// reverse the current level status if needed
}
int divide_conquer(Problem *problem, int params) {
// recursion terminator
if (problem == nullptr) {
process_result
return return_result;
}
// process current problem
subproblems = split_problem(problem, data)
subresult1 = divide_conquer(subproblem[0], p1)
subresult2 = divide_conquer(subproblem[1], p1)
subresult3 = divide_conquer(subproblem[2], p1)
...
// merge
result = process_result(subresult1, subresult2, subresult3)
// revert the current level status
return 0;
}
- 避免人肉递归
- 找到最近最简问题,将其拆解成可重复解决的逻辑
- 数学归纳法思维
分治 + 最优子结构 动态规划和分治没有本质区别,都需要找到重复子问题。两者的区别在于,动态规划需要构建最有子结构。
Bottom up + memorization
- 最优子结构 dp[n] = best_of(dp[n-1], dp[n-2], ...)
- 存储中间状态 dp[i]
- 难点在于状态的定义。
- 递归方程(状态转移方程)
- Fib:dp[i] = dp[i-1] + dp[i-2]
- 二维路径:dp[i][j] = dp[i+1][j] + dp[i][j+1]
triangle[i][j] = triangle[i][j] + min(trangle[i+1][j], triangle[i+1][j+1]
nums[i] = max(0, dp[i-1]) + nums[i]
dp[i] = min(dp[i], dp[i-coins[j]] + 1)
dp[i] = max(dp[i-1], nums[i] + dp[i-2])
一定要多做多记,先把所有细节记下来。然后不断反复,浓缩。 打破自己的惯性思维,建立机器思维 - 找重复性。
DP三步
- 分治(子问题)
- 递归&记忆化 或者 建立DP表,自底向上
- DP方程