647._Palindromic_Substrings.md 4.0 KB
Newer Older
K
KEQI HUANG 已提交
1
### 647. Palindromic Substrings
K
KEQI HUANG 已提交
2 3 4 5 6 7 8 9 10 11 12 13 14

题目:
<https://leetcode.com/problems/Palindromic-Substrings/>


难度:

Medium


思路

这道题要求给定一个字符串中的所有回文子串的个数,所以我想到了Manacher算法,
K
KEQI HUANG 已提交
15 16
[Manacher算法](https://www.felix021.com/blog/read.php?2040) 

K
KEQI HUANG 已提交
17 18
Manacher算法增加两个辅助变量id和mx,其中id表示最大回文子串中心的位置,mx则为id+P[id],也就是最大回文子串的边界。得到一个很重要的结论:

K
KEQI HUANG 已提交
19
- 如果mx > i,那么P[i] >= Min(P[2 * id - i], mx - i) . 为什么这样说呢,下面解释
K
KEQI HUANG 已提交
20 21 22 23

下面,令j = 2*id - i,也就是说j是i关于id的对称点。

- 当 mx - i > P[j] 的时候,以S[j]为中心的回文子串包含在以S[id]为中心的回文子串中,由于i和j对称,以S[i]为中心的回文子串必然包含在以S[id]为中心的回文子串中,所以必有P[i] = P[j];
K
KEQI HUANG 已提交
24
![](https://github.com/Lisanaaa/myTODOs/blob/master/manacher1.png)
K
KEQI HUANG 已提交
25 26

- 当 P[j] >= mx - i 的时候,以S[j]为中心的回文子串不一定完全包含于以S[id]为中心的回文子串中,但是基于对称性可知,下图中两个绿框所包围的部分是相同的,也就是说以S[i]为中心的回文子串,其向右至少会扩张到mx的位置,也就是说 P[i] >= mx - i。至于mx之后的部分是否对称,再具体匹配。
K
KEQI HUANG 已提交
27 28
![](https://github.com/Lisanaaa/myTODOs/blob/master/manacher2.png)
所以P[i] >= Min(P[2 * id - i], mx - i),因为以j为中心的绘回文子串的左边界可能会比mx关于id的对称点要大,此时只能证明P[i]=P[2 * id - i]
K
KEQI HUANG 已提交
29
- 此外,对于 mx <= i 的情况,因为无法对 P[i]做更多的假设,只能让P[i] = 1,然后再去匹配。
K
KEQI HUANG 已提交
30
此题还可以借鉴我leetcode第5题的解析,
K
KEQI HUANG 已提交
31
[thining-in-lc-5](https://github.com/Lisanaaa/thinking_in_lc/blob/master/005._longest_palindromic_substring.md)
K
KEQI HUANG 已提交
32

K
KEQI HUANG 已提交
33 34 35 36 37
这道题的基本思想是将以每一个字符为中心的回文子串个数相加,还是用一个小例子来解释
![](https://github.com/Lisanaaa/myTODOs/blob/master/manacher3.jpg)
其实,以‘#’为中心的回文子串就代表这个子串的长度是偶数,类似于'abba'这种
但是其实这个字符本身也是一个回文子串,所以叠加的形式是count += (P[i]+1)/2,为什么呢,以下是解释:
- 对于每一个以字符‘#’为中心的回文子串,其P值绝对是偶数,所以```(P[i]+1)/2 = P[i]/2```,并不影响
K
KEQI HUANG 已提交
38
- 对于每一个以非字符‘#’为中心的回文子串,其P值绝对是奇数,这就保证了单个字母的回文子串(```例如'a'也算一个回文子串```)也被加起来了,因为```(P[i]+1)/2 = P[i]/2+1```
K
KEQI HUANG 已提交
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72


```python
class Solution(object):
    def countSubstrings(self, s):
        """
        :type s: str
        :rtype: str
        """
        def preProcess(s):
            if not s:
                return ['^', '$']
            T = ['^']
            for c in s:
                T += ['#', c]
            T += ['#', '$']
            return T
        T = preProcess(s)
        P = [0] * len(T)
        id, mx, count = 0, 0, 0
        for i in range(1,len(T) - 1):
            j = 2*id - i
            if mx > i:
                P[i] = min(mx - i, P[j])
            else:
                P[i] = 0
            while T[i+P[i]+1] == T[i-P[i]-1]:
                P[i] += 1
            if (i + P[i]) > mx:
                id, mx = i, i + P[i]
        for i in range(len(P)):
            count += (P[i]+1)/2
        return count
```
K
KEQI HUANG 已提交
73
python无敌啊!!!有没有天理啊,手动滑稽😏😏😏😏!一行解法:
K
KEQI HUANG 已提交
74 75 76 77 78 79 80 81 82 83 84
```python
class Solution(object):
    def countSubstrings(self, s):
        """
        :type s: str
        :rtype: int
        """
        return sum(len(os.path.commonprefix((s[:i][::-1], s[i:]))) 
                   + len(os.path.commonprefix((s[:i][::-1], s[i + 1:]))) + 1 
                        for i in range(len(s)))
```
K
KEQI HUANG 已提交
85 86 87
解释下为啥要加两次,因为回文串有以下两种形式:
- ‘abcba’
- 'abba'
K
KEQI HUANG 已提交
88

K
KEQI HUANG 已提交
89
那为啥要加那个1呢,上面解释过了,单个字符也算是一个回文子串呀,嘻嘻😁