一种递归转动态规划的方法
FROM左神的视频。
参考的博客
递归
递归解题的思路:
- 大问题可以分解成小问题,小问题的解可以合成为大问题的解
- 必须有明确的退出条件(base case【左神的base case】)
- 通解的返回值应该如何考虑,这往往是比较复杂的。
递归1:二叉搜索树转双向链表
思路:根据二叉树的递归中序遍历的框架写的代码。
package com.tom.offer;
import java.util.Objects;
import java.util.Stack;
public class Ch27_ConvertBinarySearchTree {
public static void main(String[] args) {
TreeNode treeNode = TreeNode.buildTree(5);
TreeNode.levelPrintTreeNode(treeNode);
System.out.println();
inOrder(treeNode);
System.out.println();
TreeNode treeNode1 = convertBinarySearchTree(new Stack<>(), treeNode);
while(Objects.nonNull(treeNode1)){
System.out.print(treeNode1.value + " ");
treeNode1 = treeNode1.right;
}
System.out.println();
}
public static void inOrder(TreeNode treeNode) {
if(Objects.isNull(treeNode)){
return;
}
inOrder(treeNode.left);
System.out.print(treeNode.value + " ");
inOrder(treeNode.right);
}
public static TreeNode convertBinarySearchTree(Stack<TreeNode> stack, TreeNode treeNode) {
TreeNode head = null;
if(Objects.nonNull(treeNode.left)) {
//只要左子树的,因head一定是左子树中最左的节点
head = convertBinarySearchTree(stack,treeNode.left);
}
if(stack.isEmpty()){
//找到head,记录
head = treeNode;
stack.push(treeNode);
}else {
//通常情况下,双向链表的基本操作
TreeNode pop = stack.pop();
stack.push(treeNode);
pop.right = treeNode;
treeNode.left = pop;
}
if(Objects.nonNull(treeNode.right)) {
//右子树
convertBinarySearchTree(stack,treeNode.right);
}
return head;
}
}
递归2:字符串的所有的字串
#include <functional>
#include <string>
#include <iostream>
using namespace std;
void printAllSub(string str, int i, string res){
if (i == str.length()){
cout << res << endl;
return;
}
//要与不要,超想要哈哈哈
printAllSub(str, i+1, res);
printAllSub(str, i+1, res + str.at(i));
}
int main(int argv, char** argc){
string test = "abc";
printAllSub(test, 0, "");
}
递归3:矩阵的最小路径
有一个矩阵map,它每个格子有一个权值。从左上角的格子开始每次只能向右或者向下走,最后到达右下角的位置,路径上所有的数字累加起来就是路径和,返回所有的路径中最小的路径和。
测试样例:[[1, 2, 3], [1, 1, 1]]
返回:4
思路:假如你已经到达矩阵中的某一个格子,那么当前格子最小的路径和是怎么来的呢?
从图中可以看出,肯定是从当前格子的左边,或者上边走过来的。因此当前格子最小的路径和是min(左边,上边) + 当前格子的权值
int process1(vector<vector<int>> matrix, int i, int j){
// i, j表示行数和列数
if(i == 0 && j == 0){
return matrix[i][j];
}
if(i != 0 && j == 0){
//第一列
return process1(matrix, i - 1, j) + matrix[i][j];
}
if(i == 0 && j !=0){
//第一行
return process1(matrix, i, j - 1) + matrix[i][j];
}
//通常情况
return matrix[i][j]+ min(process1(matrix, i, j - 1), process1(matrix, i - 1, j));
}
int minPath1(vector<vector<int>> matrix){
return process1(matrix, matrix.size()-1, matrix[0].size()-1);
}
动态规划
动态1: 矩阵的最小路径
思路:写好递归代码,根据base case写已知
1.
if(i == 0 && j == 0){
return matrix[i][j];
}
2.
if(i == 0 && j !=0){
//第一行
return process1(matrix, i, j - 1) + matrix[i][j];
}
3.
if(i != 0 && j == 0){
//第一列
return process1(matrix, i - 1, j) + matrix[i][j];
}
4.
完整代码
int minPath2(vector<vector<int>> matrix){
if(matrix.size() == 0 || matrix[0].size() == 0){
return 0;
}
int row = matrix.size();
int col = matrix[0].size();
vector<vector<int>> dp(row, vector<int>(col)); //二维vector初始化的方式
dp[0][0] = matrix[0][0];
for(int i = 1;i < row; i++){
dp[i][0] = dp[i-1][0] + matrix[i][0];
}
for(int j = 1;j < col; j++){
dp[0][j] = dp[0][j-1] + matrix[0][j];
}
for(int i = 1;i < row; i++){
for(int j = 1;j < col; j++){
dp[i][j] = matrix[i][j] + min(dp[i-1][j], dp[i][j-1]);
}
}
return dp[row - 1][col - 1];
}
动态2: 打印矩阵的最小路径
如果要打印路径的话,还是要用动态规划吧。
package com.tom.offer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
public class Ch49_StrToInt {
public static void main(String[] args) {
int[][] matrix = new int[][]{
{
1,7,9,2},
{
8,6,3,2},
{
1,6,7,8},
{
2,9,8,2}};
List list = minPath2(matrix);
list.forEach(System.out::println);
}
public static List minPath2(int[][] matrix){
if(matrix.length == 0 || matrix[0].length == 0){
return Collections.emptyList();
}
int row = matrix.length;
int col = matrix[0].length;
int[][] dp = new int[row][col];
dp[0][0] = matrix[0][0];
for(int i = 1;i < row; i++){
dp[i][0] = dp[i-1][0] + matrix[i][0];
}
for(int j = 1;j < col; j++){
dp[0][j] = dp[0][j-1] + matrix[0][j];
}
for(int i = 1;i < row; i++){
for(int j = 1;j < col; j++){
dp[i][j] = matrix[i][j] + Math.min(dp[i-1][j], dp[i][j-1]);
}
}
//倒推路径
int i = row - 1, j = col - 1;
List<Integer> list = new ArrayList<>();
while(i != 0 || j != 0){
list.add(matrix[i][j]);
if(j == 0 || (i > 0 && dp[i - 1][j] + matrix[i][j] == dp[i][j])){
--i;
}else if(i == 0 || (j > 0 && dp[i][j - 1] + matrix[i][j] == dp[i][j])){
--j;
}
}
list.add(matrix[0][0]);
Collections.reverse(list);
return list;
}
}