[leetCode-516Longest Palindromic Subsequence]最长回文子序列DP算法详解

来源:互联网 发布:范玮琪人品知乎 编辑:程序博客网 时间:2024/06/06 10:48

一、题目描述
问题较为简单,给定一个字符串,如"aasasbc",计算出该字符串中最长的回文子序列长,即为"aaa"的长度3,回文子序列是指顺序和倒序均为同一个字符串的序列,另外,要求所输入的字符串长度不大于1000。
二、思路解析
分治算法去解决这道题是第一思路,即对于一个长度为n的字符串,对应于一个分治算法的状态数组dp[n-1][n-1],该数组的值对应字符串中最长回文子序列的长度,如dp[i][j]则代表着字符串中第i位到第j位的子序列中的最长回文子序列长度为dp[i][j],明确这一点后,我们要作的即为求出dp[0][n-1]的值并输出即可。
利用分治算法的思想,当某子串s(i,j)中s[i]与s[j]相等时,那么其头尾两字符一定位于其最长回文子串中,因此该子串的最长回文子序列长度等于去掉头尾两字符后新子串的最长回文子序列长度加二,我们可制定公式如下:dp[i][j] = dp[i + 1][j - 1] + 2。当s[i]与s[j]不相等时,则dp[i][j] = max(de[i + 1][j],dp[i][j - 1])。有了这个规则,我们接下来只需要遍历出该字符串s的每一个子串,即dp数组中的每一个值,最终输出dp[0][n-1]。
三、代码实现
根据分治算法,首先想到的是函数递归,这种方法虽然能得到正确的结果,但是时间复杂度却不能满足题目要求,当输入序列变得复杂时,计算时间远远大于规定时间。分治算法递归函数的实现代码如下:

class Solution {public:    int longestPalindromeSubseq(string s) {        int len = s.size();        return longestSub(s,0,len - 1);    }    int longestSub(string s1,int begin, int end) {        if(begin == end) return 1;        if(begin > end) return 0;        if(s1[begin] == s1[end]) {            return longestSub(s1,begin + 1,end - 1) + 2;        } else {            return max(longestSub(s1,begin + 1,end),longestSub(s1,begin,end - 1));        }    }};
后来发现老是超时,琢磨着可能是递归函数的时间复杂度太高,于是变换思路,采用一个O(n^2)的时间复杂度算法去遍历给定序列的每一个子序列,并计算每一个子序列的最长回文子串,实现代码如下:

class Solution {public:    int longestPalindromeSubseq(string s) {        int len = s.size();        int i, j;        vector<vector<int>> dp(len,vector<int>(len,0));        if(len == 0 || len == 1) return len;        for(j = 0;j < len;j++) {            dp[j][j] = 1;            for(i = j - 1; i >= 0;i--) {                if(s[i] == s[j]) {                    dp[i][j] = dp[i + 1][j - 1]+ 2;                } else {                    dp[i][j] = max(dp[i + 1][j],dp[i][j - 1]);                }            }        }        return dp[0][len - 1];    }  };



阅读全文
0 0
原创粉丝点击