19 flask之藍圖
647. 迴文子串 - 力扣(LeetCode) (leetcode-cn.com)
方法1:中心擴充套件--遍歷中心/遍歷中心種類
假設字串長度n=4。
迴文左起始位置 | 迴文右起始位置 | |
0 | 0 | 0 |
1 | 0 | 1 |
2 | 1 | 1 |
3 | 1 | 2 |
4 | 2 | 2 |
5 | 2 | 3 |
6 | 3 | 3 |
可以看出中心種類有7中,可得公式s=2*n-1,程式碼如下;
public int countSubstrings(String s) { int n = s.length(), ans = 0; for (int i = 0; i <=2*n-1; ++i) { int l = i / 2, r = i / 2 + i % 2; while (l >= 0 && r < n && s.charAt(l) == s.charAt(r)) { --l; ++r; ++ans; } } return ans; }方法2:manacher演算法
public int countSubstrings(String s) {
int n = s.length();
StringBuffer t = new StringBuffer("$#");
for (int i = 0; i < n; ++i) {
t.append(s.charAt(i));
t.append('#');
}
n = t.length();
t.append('!');//第一個與最後一個字元不同,中心擴充套件時無需判斷邊界可安全退出
int[] f = new int[n];
int iMax = 0, rMax = 0, ans = 0;
for (int i = 1; i < n; ++i) {
// 初始化 f[i]
f[i] = i <= rMax ? Math.min(rMax - i + 1, f[2 * iMax - i]) : 1;//rMax-i+1防止f[2*iMax-i]過大超過右邊界
// 中心拓展
while (t.charAt(i + f[i]) == t.charAt(i - f[i])) {
++f[i];
}
// 動態維護 iMax 和 rMax
if (i + f[i] - 1 > rMax) {
iMax = i;
rMax = i + f[i] - 1;
}
// 向上取整,f[i]初始為1,所以除二即可
ans += f[i] / 2;
}
return ans;
}
時間複雜度:O(n))。即 Manacher 演算法的時間複雜度,由於最大回文右端點 r_mrm只會增加而不會減少,故中心拓展進行的次數最多為 O(n)O(n),此外我們只會遍歷字串一次,故總複雜度為 O(n)O(n)。
空間複雜度:O(n)。