• 动态规划公共子问题模式总结


    动态规划公共子问题模式

    在解决动态规划问题时候, 关键的一点就是找到子问题, 在动态规划中有一些常见的子问题模式,需要熟悉。下面就是一些常见子问题模式总结


    1. 输入为x1,x2,···, xn输出为x1,x2, ···, xi

    在这里插入图片描述

    在这种情况下,子问题是从x1~xi这一部分。
    子问题的个数一般为n, 所以用一个dp[n]的数组就能把子问题的解保存

    例子:LeetCode746 Min Cost Climbing Stairs(爬上楼梯的最小损失)

    博客地址:
    https://blog.csdn.net/qq874455953/article/details/82564279

    此题利用的就是求当前的dp[i], 要用到前面的dp[i-1]和dp[i-2]. 也就是说子问题是由前面的x1~xi-1得到的。

    class Solution {
    public:
        int minCostClimbingStairs(vector<int>& cost) {
            //定义一个数组 表示爬上每一层楼梯 需要的最少cost
            vector<int> dp(cost.size(), 0);
            //第一层楼梯和第二层楼梯的cost就是本身
            dp[0] = cost[0];
            dp[1] = cost[1];
            //现在循环计算 后面每一层的最小cost
    
            for (int i = 2; i < cost.size(); i++) {
                dp[i] = min(dp[i-2] + cost[i], dp[i-1] + cost[i]);
            }
    
            //到达楼梯终点的最小cost 就是倒数第一层和第二层的最小cost值
            return min(dp[cost.size()-2] , dp[cost.size()-1]);
        }
    };
    

    2. 输入为x1,x2,···, xn和y1,y2,···, yn, 输出为x1,x2, ···, xi和y1,y2,···, yi

    在这里插入图片描述

    在这种情况下, 子问题个数一般为m * n, 所以用dp[m][n] 就能把子问题的解保存

    例子:编辑距离

    博客地址
    https://blog.csdn.net/qq_36124194/article/details/83716115

    输入为两个字符串, 也就是x1 ··· xm , y1 ··· yn ,解的结果是在两个字符串前面的子字符串产生。

    class Solution {
    public:
        int minDistance(string word1, string word2) {
            int size1 = word1.size();
            int size2 = word2.size();
            vector<vector<int>> count(size1+1, vector<int>(size2+1, 0));
            for(int i = 0; i <= size1; i++) {
            	count[i][0] = i;
            }
            for(int i = 0; i <= size2; i++) {
            	count[0][i] = i;
            }
    
            for(int i = 1; i <= size1; i++) {
            	for(int j = 1; j <= size2; j++) {
            		int tag = 0;
            		if(word1[i-1] != word2[j-1]) {
            			tag = 1;
            		}
            		count[i][j] = min(count[i-1][j]+1, count[i][j-1]+1);
            		count[i][j] = min(count[i][j], tag+count[i-1][j-1]);
            	}
            }
            return count[size1][size2];
        }
    };
    

    3. 输入为x1,x2,···, xn, 输出为xi,xi+1,···, xj.

    在这里插入图片描述

    这种情况子问题是 中间的一部分, 所以情况是n*n, 子问题的个数为n^2, 所以用**dp[n][n]**就能把子问题的解保存


    4.输入为树, 输出为子树

    在这里插入图片描述

    例子:矩阵链式相乘

    假设有4个矩阵A,B,C,D, 每个矩阵的维度依次是50 * 20, 20 * 1, 1 * 10, 10 * 100, 在计算A * B * C * D 的过程中我们可能会利用矩阵相乘的结合率来优化计算,比如我们可能会这样计算 (A * B * C) * D 或者 A * ( B * C )* D , 会得到很多种计算方式,其中有没有什么方式计算量最少呢?
    在这里插入图片描述

    我们可以看到

    在这里插入图片描述

    不同方式会产生巨大差异

    其实我们可以把不同的计算顺序看成一颗二叉树, 例如在这里插入图片描述

    那么子问题就是这个树的子树 动态规划就变成了求子树的最优值。

  • 相关阅读:
    MySQL实现嵌套集合模型
    Go项目结构和模块导入
    sqlalchemy(二)高级用法
    sqlalchemy(一)基本操作
    K-均值聚类算法
    回归
    logistic回归
    Android隐藏状态栏、导航栏
    Android监听返回键、Home键+再按一次返回键退出应用
    PDFMate PDF Converter Pro
  • 原文地址:https://www.cnblogs.com/qq874455953/p/10264448.html
Copyright © 2020-2023  润新知