给你一个下标从 0 开始的字符串 s
,你需要找到两个 不重叠的回文 子字符串,它们的长度都必须为 奇数 ,使得它们长度的乘积最大。
更正式地,你想要选择四个整数 i
,j
,k
,l
,使得 0 <= i <= j < k <= l < s.length
,且子字符串 s[i...j]
和 s[k...l]
都是回文串且长度为奇数。s[i...j]
表示下标从 i
到 j
且 包含 两端下标的子字符串。
请你返回两个不重叠回文子字符串长度的 最大 乘积。
回文字符串 指的是一个从前往后读和从后往前读一模一样的字符串。子字符串 指的是一个字符串中一段连续字符。
示例 1:
```txt
输入:s = "ababbb"
输出:9
解释:子字符串 "aba" 和 "bbb" 为奇数长度的回文串。乘积为 3 * 3 = 9 。
```
示例 2:
```txt
输入:s = "zaaaxbbby"
输出:9
解释:子字符串 "aaa" 和 "bbb" 为奇数长度的回文串。乘积为 3 * 3 = 9 。
```
提示:
2 <= s.length <= 10^5
s
只包含小写英文字母。
两个回文子字符串长度的最大乘积
题目
给你一个下标从 0 开始的字符串 s
,你需要找到两个 不重叠****的回文 子字符串,它们的长度都必须为 奇数 ,使得它们长度的乘积最大。
更正式地,你想要选择四个整数 i
,j
,k
,l
,使得 0 <= i <= j < k <= l < s.length
,且子字符串 s[i...j]
和 s[k...l]
都是回文串且长度为奇数。s[i...j]
表示下标从 i
到 j
且 包含 两端下标的子字符串。
请你返回两个不重叠回文子字符串长度的 最大 乘积。
回文字符串 指的是一个从前往后读和从后往前读一模一样的字符串。子字符串 指的是一个字符串中一段连续字符。
示例 1:
1 | 输入:s = "ababbb" |
示例 2:
1 | 输入:s = "zaaaxbbby" |
提示:
-
2 <= s.length <= 10^5
s
只包含小写英文字母。
题解
方法一:
思路
关键思路
找到以s[i]
为中心的最长回文串长度span[i]
。
接下来预处理出两个数组l
和r
。
l[i]
代表s[0...i]
内最长奇数回文串长度。
r[i]
代表s[i...n-1]
内最长奇数回文串长度。
枚举维护最大的l[i-1]*r[i], 1<i<n
即为答案。
首先求s[i]
为中心的最长回文串长度。
我们可以用字符串哈希+二分法来做,时间复杂度$O(nlogn)$,
也可以用马拉车算法,时间复杂度$O(n)$。
接下来讲述一下字符串哈希+二分的思路。
对于每个s[i]
为中心的最长回文串长度如果为m,那么m-2也是以s[i]
为中心的回文串。也就是说具有单调性,可以二分找出由小到大最后于一个满足的长度。时间复杂度$O(logn)$,总共有n个点所以需要$O(nlogn)$的时间复杂度。
然后一个难点就是l和r数组。
对于第s[i]
可以对l[i+span[i]]
做贡献,让其于i+span[i]
取最大值。
同理第s[i]
可以对r[i-span[i]]
做贡献,让其于i-span[i]
取最大值。
然后从前向后遍历取l前缀最大值,从后向前遍历取r后缀最大值。
做这里还没有结束。这里还有一个很大的坑
需要由大到小让l[i] = max(l[i], l[i+1]-2)
。如果i+1
是一个以l[i+1]
长度结尾的回文,那么l[i]
在此基础上去掉首位所以长度为l[i+1]-2
同理r[i] = max(r[i], r[i-1]-2)
代码
1 | class Solution { |
方法二:
思路
关键思路同题解一。
不同点在于求s[i]
为中心的最长回文串长度。用马拉车算法,时间复杂度$O(n)$。
设$span_i$为以i为中心的回文半径。在可以让我们知道所有以i为中心的奇数长度回文串。这个回文半径不包含中心,也就是说"abcba"
,'c'
的回文半径是2。
$d$为遍历到当前回文串最远覆盖的下标,即$d = max(span_j+j), j \in [0, i-1]$。
设$c$为满足$d = max(span_j+j), j \in [0, i-1]$的$j$。
在求$span_i$时,$span_j,j<i$已经全部求出,对于求$span_i$:
在$i\le r$时,分两种情况:
- 当$span_i \le r$, 这时$span_i = span_j$, $j$是$i$关于$m$对称的点。即$span_i = span_{i-2m}$
- 当$span_i > r$, 对于大于$r$的部分用中心扩散法,所以可以先让$span_i = r-i$
由这两种情况可知让$span_i = min(r-i, span_{i-2m})$, 然后再做中心扩散法。
在$i>r$时,直接使用中心扩散法。
最后便可求得$span$数组。以下标$i$为中心的回文串为[i-span[i]...span[i]+i]
代码
1 | class Solution { |