回文子串
暴力解法
两层for循环,遍历区间起始位置和终止位置,还需一层遍历判断这个区间是不是回文,时间复杂度是On^3
动态规划
五部曲
- 确定dp数组,基于回文的特性,我们需要把dp数组定义成二维dp数组,
dp[i][j],区间[i, j]的子串是否是回文子串 - 确定递推公式
s[i] !== s[j],dp[i][j] = falses[i] === s[j]- 当
i===j,一个字符,是回文子串 - 当i和j相差1,是回文子串
- 当i和j相差大于1,依赖于
[i+1, j-1]区间是不是回文子串
- 当
if(s[i] !== s[j]) {
dp[i][j] = false
} else {
if(j - i <= 1) {
result++
dp[i][j] = true
} else if(dp[i+1][j-1]) {
result++
dp[i][j] = true
}
}
- dp数组初始化,都初始化为false
- 确定遍历顺序,
dp[i+1][j-1]在dp[i][j]的左下角,所以一定要从下到上,从左到右遍历 - 举例推导
时间复杂度:O(n^2) 空间复杂度:O(n^2)
/**
* @param {string} s
* @return {number}
*/
var countSubstrings = function(s) {
let result = 0
let dp = new Array(s.length).fill(0).map(_ => new Array(s.length).fill(false))
for(let i = s.length - 1; i >= 0;i--) {
for(let j = i;j < s.length;j++) {
if(s[i] !== s[j]) {
dp[i][j] = false
} else {
if(j - i <= 1) {
result++
dp[i][j] = true
} else if(dp[i+1][j-1]){
result++
dp[i][j] = true
}
}
}
}
return result
};
双指针法
找中心然后向两边扩散看是不是对称
以一个元素为中心点或者以两个元素为中心点
时间复杂度:O(n^2) 空间复杂度:O(1)
/**
* @param {string} s
* @return {number}
*/
var countSubstrings = function (s) {
function extend(i, j) {
let res = 0
while (i >= 0 && j < s.length && s[i] === s[j]) {
i--
j++
res++
}
return res
}
let result = 0
for (let i = 0; i < s.length; i++) {
result += extend(i, i)
result += extend(i, i+1)
}
return result
};
最长回文子序列
和回文子串的区别在于
回文子序列不是连续的,回文子串是要连续的
五部曲
- 确定dp数组以及下标的含义,
dp[i][j]表示字符串在[i,j]内的最长回文子序列的长度 - 确定递推公式
s[i] === s[j],则dp[i][j] = dp[i+1][j-1] + 2s[i] !== s[j]- 加入
s[i],不要s[j],dp[i][j-1] - 加入
s[j],不要s[i],dp[i+1][j] - 则
dp[i][j] = Math.max(dp[i+1][j], dp[i][j-1])
- 加入
- 初始化,当i等于j的时候,初始化为1,其他情况初始化为0
for(let i=0; i < s.length; i++) {
dp[i][i] = 1
}
- 确定遍历顺序, 从下到上遍历,从左到右遍历
- 举例推导
时间复杂度: O(n^2) 空间复杂度: O(n^2)
/**
* @param {string} s
* @return {number}
*/
var longestPalindromeSubseq = function (s) {
let dp = new Array(s.length).fill(0).map(_ => new Array(s.length).fill(0))
for (let i = 0; i < s.length; i++) dp[i][i] = 1
for(let i = s.length - 1; i >=0;i--) {
for(let j = i + 1; j < s.length;j++) {
if(s[i] === s[j]) {
dp[i][j] = dp[i+1][j-1] + 2
} else {
dp[i][j] = Math.max(dp[i+1][j], dp[i][j-1])
}
}
}
return dp[0][s.length-1]
};