LeetCode 5. Longest Palindromic Substring(C++ 动态规划)

5. Longest Palindromic Substring
题意为给定一个字符串s,找出字符串s中的最长回文子串并输出。回文是指字符串重左向右读和从右向左读是一样的。注意题目说明假设最长字符数长度为1000

Example 1:
Input: “babad”
Output: “bab”
Note: “aba” is also a valid answer.

Example 2:
Input: “cbbd”
Output: “bb”

思路1:(brute force 暴力求解 O(n^3)会超时 )
对于字符串s,取其所有的子串,判断取出的该子串是否是回文串,并找出最长的回文子串输出即可。

取子串的具体做法是,设置子串的起始下标i,和结束下标j,用两重循环遍所有子串的判断取出的子串是否为回文串(取子串O(n^2))。

对于判断回文串,可把字符串s逆序,然后判断逆序后的字符串和原来的字符串是否相等,相等即为回文串(这里逆序时间复杂度为O(n)),每次取子串都需要判断是否是回文串,所以总的时间复杂度为O(n^3)。

C++代码

//brute force
class Solution {
public:
    string longestPalindrome(string s) {
        if(s=="")
            return "";
        int max = 0;
        string result;
        for(int i = 0; imax){
                    result = substr;
                    max = substr.length();
                }
            }
        }
        return result;
    }
    
    bool isPalindromic(string substring){//the time complexity of this function is O(n^3)
        string copy = substring;
        reverse(copy.begin(), copy.end());
        return copy == substring;
    }
    
};

看了提示说这题可以使用动态规划,但是还是没有什么头绪,找不到递推公式。
思路2:动态规划(O(n^2))
设置一个二维数组dp,大小为s.length() x s.length(),数组dp[i][j]=1表示字符串s的子串si…sj(子串si到sj)为回文串,dp[i][j]=0表示该子串为非回文串。

动态规划的边界条件为:
dp[i][i]=1(长度为1的子串必为回文串)
dp[i][i+1]= (s[i]==s[i+1])(如果长度为2的子串两个字符相等则为回文子串)

状态转移方程
dp[i][j] = (dp[i+1][j-1] && s[i]==s[j]),如果一个子串本身就为回文串,那么该子串左右两边加上一样的任意字符还是回文串

通过上述思路可以发现,该题是按子串的长度进行递推的,即先判断所有长度为1的子串是否为回文串,然后再判断所有长度为2的子串是否为回文串,然后依次判断长度为3,4,…的子串是否为回文串,这样可以知道对数组dp的递推是按主对角线(左上到右下的那条线)依次向上递推。

复杂度分析
时间复杂度O(n^2):取子串依旧是O(n2),判断是否为回文串为O(1),所以总的时间复杂度为O(n2)
空间复杂度O(n^2):维护状态数组dp,大小为s.length x s.length()

这题使用动态规划和平常不太一样,一般的题型我一般是从递归转换为动规,减少递归时过多的重复计算从而提高效率,但是这题对判断子串是否为回文串使用动规去判断,因为实际上判断回文串存在许多重复计算,小的子串的判断对后续更大的子串的判断有帮助(考虑在原有子串两边增加字符再判断O(1)),所以使用动规可以减小时间复杂度。如果不使用动规,每次傻傻的遍历一遍字符串判断是否是回文串,当s太长容易超时。

C++代码

class Solution {
public:
    string longestPalindrome(string s) {
        if(s=="")
            return "";
        vector > dp(s.size(), vector(s.size(), 0));
        int start = 0, end = 0, max = 0;
        //initialize the basic case
        for(int i = 0;imax){
                        start = i;
                        end = j;
                        max = j-i;
                    }
                }
            }
        }
        return s.substr(start, end+1-start);
    }
};

你可能感兴趣的:(Leetcode,动态规划)