动态规划算法总结(java)

什么是动态规划

  • 动态规划是一种多阶段决策最优解模型,一般用来求最值问题,多数情况下它可以采用自下而上的递推方式来得出每个子问题的最优解(即最优子结构),进而自然而然地得出依赖子问题的原问题的最优解。
  • 最优子结构性质
  • 重叠子问题性质
  • 状态之间满足无后效性
  • 自底向上算法

判断题目是否能用动态规划

  1. 判断是否可用递归来解
  2. 分析在递归的过程中是否存在大量的重复子问题
  3. 采用备忘录的方式来存子问题的解以避免大量的重复计算(剪枝)
  4. 改用自底向上的方式来递推(状态转移方程),即动态规划

该类题目的解决方法

  1. 第一种:使用自顶向下的(递归+备忘录)方法
  2. 第二种:使用自底向上的动态规划算法
  • 第一种方法中的备忘录和第二种方法中的dp table本质上是一样的,两种方法效率差不多
  • 无论是备忘录还是dp table本质上进行了暴力算法求解树的剪枝过程,也就是对重叠子问题仅仅求解一次
  • 所以动态规划算法是聪明的暴力求解,体现于它的剪枝操作

动态规划三要素

  • 问题的阶段
  • 每个阶段的状态
  • 从前一个阶段转化到后一个阶段之间的递推关系

经典问题

0-1背包问题
public class Solution {
    public int knapsack(int[] w, int[] v, int capacity) {
        int[][] dp = new int[w.length+1][capacity+1];
        
        for (int i=1; i<=w.length; i++) {
            for (int j=0; j<=capacity; j++) {
                if (w[i-1] >j) {
                    dp[i][j] = dp[i-1][j];
                } else {
                    dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j-w[i-1]]+v[i-1]);
                }
            }
        }
        return dp[w.length][capacity];
    }
}
leetcode5. 最长回文子串
class Solution {
    public String longestPalindrome(String s) {
        int len = s.length();
        if (len == 0) {
            return s;
        }
        boolean[][] dp = new boolean[len][len];

        int start = 0, maxLen = 1;
        for (int j = 0; j < len; j++) {
            for (int i = 0; i <= j; i++) {
                if (s.charAt(i) == s.charAt(j)) {
                    if (j - i < 3) {
                        dp[i][j] = true;
                    } else {
                        dp[i][j] = dp[i + 1][j - 1];
                    }
                } else {
                    dp[i][j] = false;
                }
                if (dp[i][j]) {
                    if (j - i + 1 > maxLen) {
                        start = i;
                        maxLen = j - i + 1;
                    }
                }
            }
        }
        return s.substring(start, start + maxLen);
    }
}
leetcode1143. 最长公共子序列
class Solution {
    public int longestCommonSubsequence(String text1, String text2) {
        int[][] dp = new int[text1.length()+1][text2.length()+1];

        for (int i=0; i<text1.length(); i++) {
            for (int j=0; j<text2.length(); j++) {
                if (text1.charAt(i) == text2.charAt(j)) {
                    dp[i+1][j+1] = dp[i][j] + 1;
                } else {
                    dp[i+1][j+1] = Math.max(dp[i][j+1], dp[i+1][j]);
                }
            }
        }
        return dp[text1.length()][text2.length()];
    }
}

分治策略,贪心与动态规划

  • 分治策略解决子问题互相独立且与原问题形式相同的问题,大多用递归解决
  • 动态规划解决具有重叠子问题性质的问题,可用递归+备忘录解决,也可以用自底向上迭代解决
  • 贪心算法解决具有贪心选择性质的问题,可用递归也可迭代解决
  • 动态规划之所以高效,就是因为回溯算法实现中存在大量的重复子问题
  • 计算机解决问题其实没有任何奇技淫巧,它唯一的解决办法就是穷举,穷举所有可能性。算法设计无非就是先思考“如何穷举”,然后再追求“如何聪明地穷举”。

你可能感兴趣的:(算法)