<Leetcode> 由Longest Palindromic Substring再看DP

1. 题目

这里写图片描述

2. 分析

  官网有DP的分析,但是没有直接给出代码实现。经过之前的背包9讲的学习,可以很快写出状态定义: F [ i , j ] 表示字符串从 i j 的最长子串,然后状态转移方程为
  

F [ i , j ] = F [ i + 1 , j 1 ] ,     i f   s [ i ] == s [ j ]

该状态转移方程的初始条件可能有两种情况: i == j , i == j 1 到这里只是DP分析的第一步,因为我们明显写出来了状态转移方程,所以其满足最优子结构。然后由状态转移方程可以发现其满足无后效性。
  然后写伪代码:

for i=0 to s.size()-1
    F[i][i]=1
//这里也可以当成DP小问题去做    
for i=1 to s.size()-1
    if s[i-1] == s[i]
        F[i-1][i]=F[i-1][i-1]
        update max

//这里很关键,错误的代码:
for i=0 to s.size()-2
    for j=1 to s.size()-1
        if(i != j&&s[i]==s[j])
            F[i][j]=F[i+1][j-1]
            update max

  如果从背包入门DP,一定会在这里跌倒。上面的for的上下限,将使状态转移方程不满足无后效性。可以很明显看出来F[i][j]=F[i+1][j-1]在当前的情况使未来和过去产生了关系。
  由无后效性出发,观察状态转移方程画出下图:
这里写图片描述
必须让i,j的变化满足无后效性。所以采用下面的策略:

for len=3 to s.size()
    for i=0 to s.size()-(len-1)
        j=i+(len-1)
        if  s[i] ==s[j]
            F[i][j] = F[i+1][j-1]
            update max

3. AC代码

  按照上面的分析,可以很快写出来:

class Solution {
public:
    string longestPalindrome(string s) {
        vector<vector<int>> F(s.size());
        int left=0,tmp=0,max=0;
        if(s.size() == 1)
            return s;
        for(int i=0;i<s.size();i++)
            F[i].resize(s.size());  
        for(int i=0;i<s.size();i++)
            F[i][i]=1;

        for(int i=0;i+1 < s.size();i++){
                if( s[i] == s[i+1]){
                    F[i][i+1] = F[i][i];
                    tmp=2;
                }
                else 
                    tmp=1;
                if(max < tmp){
                    left=i;
                    max=tmp;
                }
        }

        for(int len=3;len <= s.size(); len++){
            for( int i=0,j; i< s.size()-(len-1); i++){
                j=len-1+i;
                if( s[i] == s[j])
                    F[i][j] = F[i+1][j-1];
                if(F[i][j] == 1){
                    if(max < len){
                        left=i;
                        max=len;
                    }
                }
            }
        } 
        return s.substr(left,max);

    }
};

4. 总结

  笔者是记录到《DP学习系列》从零开始学习动态规划,混合背包(四)时,重新做了这个题,收获颇丰。如果单纯是看背包九讲一定会犯上面的错误,但是正是因为上面的错误,可以更加认识DP,重审最优子结构和无后效性的概念(可以重新思考背包9讲for的上下限为什么符合)。最后笔者现在对以前提出的问题有了答案(通过debug状态转移数组等等),DP的解的数量取决于初始条件中符合最优子结构的数量,但是对于每一个初始条件解是唯一的。

猜你喜欢

转载自blog.csdn.net/lovestackover/article/details/80603871