「这是我参与11月更文挑战的第12天,活动详情查看:2021最后一次更文挑战」
给你一个字符串 s
,请你统计并返回这个字符串中 回文子串 的数目。
回文字符串 是正着读和倒过来读一样的字符串。
子字符串 是字符串中的由连续字符组成的一个序列。
具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。
示例 1:
输入: s = "abc"
输出: 3
解释: 三个回文子串: "a", "b", "c"
示例 2:
输入: s = "aaa"
输出: 6
解释: 6个回文子串: "a", "a", "a", "aa", "aa", "aaa"
提示:
1 <= s.length <= 1000
s
由小写英文字母组成
题解1
双层循环获取所有可能的子字符串,判断是否是回文字符串
如果是回文串,结果值 res++
代码如下:
/**
* 校验给定字符串区间是否为回文串
* @param {string} s
* @param {number} l
* @param {number} r
* @return {boolean}
*/
function check(s,l,r){
while(l<r){
if(s[l]!==s[r]) return false;
else l++,r--
}
return true;
}
var countSubstrings = function(s) {
const len = s.length;
// 因为每个字符可以是回文子串,所以初始化res为len
let res = len;
// 判断所有可能子串是否是回文串
for(let i = 0;i<len-1;i++){
for(let j = i+1;j<len;j++){
if(check(s,i,j)) res++
}
}
return res;
};
以上题解提交通过后,耗时 320ms
左右,只击败了 17%
左右的用户
因为上述题解通过双层循环求得每一种子字符串,check
内层 check
函数又对该子字符进行判断是否为回文串,时间复杂度为 O(n³)
但是如果进行优化呢?
查找所有子字符串是一个必经的过程,这里只能是 O(n²)
的时间复杂度
校验每个子字符串是否是回文串,也只能是 O(n)
的时间复杂度
想了半天没有思路,于是厚着脸皮看了官方题解
题解2
官方直接跳过了获取所有子字符串的过程,直接通过中心拓展获取所有回文子串,那么中心拓展是如何做的呢?
- 首先会通过循环枚举所有可能的回文串的中心位置,然后判断当前左右位置的字符是否相等
- 如果相等,则结果值加一,左右指针继续向外拓展
- 如果不相等,则退出本次循环 代码如下:
var countSubstrings = function(s) {
const n = s.length;
let res = 0;
// 枚举可能的回文串的中心位置,向左右扩展
// 如果相等,则找到新的回文串,res++
// 否则退出本次循环
for (let i = 0; i < 2 * n - 1; i++) {
let l = i >> 1, r = (i >> 1) + i % 2;
while (l >= 0 && r < n && s[l] == s[r]) {
res++,l--,r++
}
}
return res;
};
以上题解提交通过后,耗时 70ms
左右,击败了 90+%
用户
至此我们就完成了 leetcode-647-回文子串
如有任何问题或建议,欢迎留言讨论!