算法的动态规划思想

思路途经


1、思考状态(重点)

状态的定义,先尝试「题目问什么,就把什么设置为状态」;
然后思考「状态如何转移」,如果「状态转移方程」不容易得到,尝试修改定义,目的依然是为了方便得到「状态转移方程」。
「状态转移方程」是原始问题的不同规模的子问题的联系。即大问题的最优解如何由小问题的最优解得到。

2、思考状态转移方程(核心、难点)

状态转移方程是非常重要的,是动态规划的核心,也是难点;

常见的推导技巧是:分类讨论。即:对状态空间进行分类;

归纳「状态转移方程」是一个很灵活的事情,通常是具体问题具体分析;

除了掌握经典的动态规划问题以外,还需要多做题;

如果是针对面试,请自行把握难度。掌握常见问题的动态规划解法,理解动态规划解决问题,是从一个小规模问题出发,逐步得到大问题的解,并记录中间过程;

「动态规划」方法依然是「空间换时间」思想的体现,常见的解决问题的过程很像在「填表」。

3、思考初始化

初始化是非常重要的,一步错,步步错。初始化状态一定要设置对,才可能得到正确的结果。

角度 1:直接从状态的语义出发;

角度 2:如果状态的语义不好思考,就考虑「状态转移方程」的边界需要什么样初始化的条件;

角度 3:从「状态转移方程」方程的下标看是否需要多设置一行、一列表示「哨兵」(sentinel),这样可以避免一些特殊情况的讨论。

4、思考输出

有些时候是最后一个状态,有些时候可能会综合之前所有计算过的状态。

5、思考优化空间(也可以叫做表格复用)

「优化空间」会使得代码难于理解,且是的「状态」丢失原来的语义,初学的时候可以不一步到位。先把代码写正确是更重要;
「优化空间」在有一种情况下是很有必要的,那就是状态空间非常庞大的时候(处理海量数据),此时空间不够用,就必须「优化空间」;
非常经典的「优化空间」的典型问题是「0-1 背包」问题和「完全背包」问题。

作者:liweiwei1419
链接:https://leetcode-cn.com/problems/longest-palindromic-substring/solution/zhong-xin-kuo-san-dong-tai-gui-hua-by-liweiwei1419/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

相关LeetCode题目

最长回文子串问题(第五题)

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
暴力解法

class Solution {
    
    
    public String longestPalindrome(String s) {
    
    
        int len =s.length();
        if(len < 2)
            return s;
        int max = 1;	//回文子串的长度
        int begin = 0;
        for(int i = 0; i < len-1; i++){
    
    
            for(int j = i+1; j < len; j++){
    
    
                if( (j-i+1)>max && huiwen(s , i, j)){
    
    
                    begin = i;
                    max = j-i+1;
                }
            }
        }
        return s.substring(begin, begin+max);
    }
    public boolean huiwen(String s, int begin, int end){
    
    	//判断是否为回文子串
        while(end > begin){
    
    
            if(s.charAt(begin) == s.charAt(end)){
    
    
                begin++;
                end--;
            }else
                return false;
        }
        return true;
    }
}

执行用时 :570 ms
内存消耗 :38.2 MB,

动态规划解法
先定义状态
Boolean dp[i][j]标志字符串s 从 i ~ j 是否为回文子串

状态转移方程
dp[i][j] = true 前提为 s.charAt(i)=s.charAt(j)且dp[i+1][j-1] = true

求其初状态
二维数组dp[][]对角线必为true,

考虑输出状态

代码优化

class Solution {
    
    
    public String longestPalindrome(String s) {
    
    
        int len =s.length();
        if(len < 2)
            return s;
        int max = 1;
        int begin = 0;
        
        boolean[][] dp = new boolean[len][len];//判断i~j是否为回文子串
        for(int i = 0; i < len; i++)
            dp[i][i] = true;
        for(int j = 1; j < len; j++){
    
    
            for(int i = 0; i < j; i++){
    
    
                if(s.charAt(i) != s.charAt(j))
                    dp[i][j] = false;
                else{
    
    
                    if(j - i <3)
                        dp[i][j] = true;
                    else
                        dp[i][j] = dp[i+1][j-1];
                }
                if(dp[i][j] && j-i+1>max){
    
    
                max = j-i+1;
                begin = i;
            }
            }
        }
        return s.substring(begin,begin+max);
    }
}

执行用时:144 ms
内存消耗:42.6 MB

中心扩散解法

class Solution {
    
    
    public String longestPalindrome(String s) {
    
    
        int len =s.length();
        if(len < 2)
            return s;
        int max = 1;
        String res = s.substring(0,1);  //输出字符串
        
        for(int j = 0; j < len-1; j++){
    
     //遍历中心点
            String str1 = center(s,j,j);
            String str2 = center(s,j,j+1);
            String maxlen = str1.length() > str2.length() ? str1 : str2;
            if(maxlen.length() > max){
    
    
                max = maxlen.length();
                res = maxlen;
            }
        }
        return res;
    }
    private String center(String s, int left, int right){
    
       //中心扩散判断回文
        int i = left, j = right;
        while(i >= 0 && j <= s.length()-1){
    
    
            if(s.charAt(i) == s.charAt(j)){
    
    
                i--;
                j++;
            }else{
    
    
                break;
            }
        }
        return s.substring(i+1,j);
    }
}

执行用时:42 ms
内存消耗:40.2 MB

猜你喜欢

转载自blog.csdn.net/Leo__Lk/article/details/106602431
今日推荐