Q:
题目链接:Longest Palindromic Substring
先看题目要求:
Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.
Example1:
Input: “babad”
Output: “bab”
Note: “aba” is also a valid answer.
Example2:
Input: “cbbd”
Output: “bb”
找到一个字符串中最长的回文子串,你可以假设字符串的最大长度为1000。
分析
最直接的思路就是:写一个判断字符串是否为回文字符串的方法,然后找出字符串中所有的子串,分别执行上述方法,然后找出满足条件的最长的子串。
A:
首先写一个判断字符串是否为回文字符串的方法:
var isPalindrome = function(str, start, end){
if(str[start] !== str[end]){
return false;
}
start++;
end--;
if(end >= start){
return isPalindrome(str, start, end)
}
return true;
}
使用两个指针分别指向目标字符串的首尾,然后使用“夹逼法”递归调用,原理比较简单,看代码一路了然。还可以使用数组API reverse函数来实现这个方法:
var isPalindrome = function(str){
if(str.split('').reverse().join('') === str){
return true;
}else{
return false;
}
}
这个更简单一些,接下来看longestPalindrome函数的实现:
//取出目标字符串中的所有字串(时间复杂度为O(n2)),从长到短对每个字串执行isPalindrome方法,直到找出返回值为true的
var longestPalindrome = function(s) {
var first = 0,len = s.length;
var result = '';
while(len > 0){
first = 0;
while(first + len <= s.length){
var substr = s.substring(first, first + len)
if(isPalindrome(s, first, first + len - 1)){
len = 0;
result = substr;
break;
}
first++;
}
len--;
}
return result
};
综合两个方法,可以看到时间复杂度为O(n3)(找子串O(n2),判断是否回文O(n))。
关于动态规划,我觉得这位大神解释得比较明白易懂,可以看看什么是动态规划?动态规划的意义是什么?
首先,注意到状态转移——如果s[a][b]是回文子串,那么s[a+1][b-1]也是回文子串。反过来看,如果s[a+1][b-1]是回文子串,那么只要s[a]===s[b],则s[a][b]也为回文子串。所以,由短到长,一步步找到最长的子串。
var longestPalindrome1 = function(s) {
var dp = [];
var max = 1;
var max_start = 0;//记录最长回文子串的起始索引
//初始化二维数组
for (let i = 0; i < s.length; i++) {
dp.push([])
}
for(var end = 0;end < s.length;end++){
for(var start = 0;start < end;start++){
if(s[start] === s[end]){
//第一个判断是最初级的情况有aba aa这两种情况,一定是回文子串;第二个判断就是状态转移了
if(end - start <= 2 || dp[start+1][end-1]){
if(end - start + 1 > max){
max = end - start + 1
max_start = start;
}
dp[start][end] = true;
}
}
}
}
return s.substring(max_start, max_start + max);
};
可以看到时间复杂度为O(n2)。
这是处理该问题的大神级解法,据说时间复杂度只有O(n),具体算法请看Manacher算法总结。下面直接贴代码了:
var longestPalindrome = function(s) {
if (s.split('').reverse() === s.split('')) {
return s;
}
let maxlength = 1,
result = s[0],
start = 0,
end = 1,
arr = [];
for (let i = 0; i < s.length; i++) {
arr.push([])
}
for (let i = 0; i < s.length; i++) {
for (let j = 0; j < i; j++) {
if (s[i] === s[j]) {
arr[i][j] = 1;
}
}
}
return result;
};