KMP
java
next数组
// next[i]:模式串 s[0..i] 的「最长相等前后缀」长度
int[] buildNext(String s) {
int n = s.length();
int[] next = new int[n];
// next[0] = 0,单个字符没有真前后缀
for (int i = 1, j = 0; i < n; i++) { // j 是当前最长相等前后缀长度
// 不相等就回退 j,直到能接上或 j=0
while (j > 0 && s.charAt(i) != s.charAt(j)) j = next[j - 1];
if (s.charAt(i) == s.charAt(j)) j++; // 相等则延长
next[i] = j;
}
return next;
}
KMP匹配
int strStr(String haystack, String needle) {
int n = haystack.length(), m = needle.length();
if (m == 0) return 0;
int[] next = buildNext(needle);
for (int i = 0, j = 0; i < n; i++) { // i 遍历主串(永不回退)
// 失配:把模式串指针 j 按 next 回退
while (j > 0 && haystack.charAt(i) != needle.charAt(j)) j = next[j - 1];
if (haystack.charAt(i) == needle.charAt(j)) j++;
if (j == m) return i - m + 1; // 匹配成功,返回起点下标
}
return -1;
}
回文
java
中心扩展
String longestPalindrome(String s) {
if (s == null || s.length() < 1) return "";
int start = 0, maxLen = 0;
for (int i = 0; i < s.length(); i++) {
int len1 = expand(s, i, i); // 奇数长度:以 i 为中心
int len2 = expand(s, i, i + 1); // 偶数长度:以 i,i+1 为中心
int len = Math.max(len1, len2);
if (len > maxLen) {
maxLen = len;
start = i - (len - 1) / 2; // 由中心和长度反推起点
}
}
return s.substring(start, start + maxLen);
}
// 从中心向两边扩,返回回文长度
int expand(String s, int l, int r) {
while (l >= 0 && r < s.length() && s.charAt(l) == s.charAt(r)) { l--; r++; }
return r - l - 1; // 退出时多走了一步,故 -1
}
区间DP求回文
// dp[i][j]:s[i..j] 内最长回文子序列长度。按区间长度从小到大
int longestPalindromeSubseq(String s) {
int n = s.length();
int[][] dp = new int[n][n];
for (int i = n - 1; i >= 0; i--) { // i 倒序,保证算 [i][j] 时 [i+1][*] 已就绪
dp[i][i] = 1;
for (int j = i + 1; j < n; j++) {
if (s.charAt(i) == s.charAt(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][n-1];
}
Manacher
// 插入分隔符 '#' 把奇偶统一成奇数长度,维护最右回文边界 R 和其中心 C
String preProcess(String s) {
StringBuilder sb = new StringBuilder("^#");
for (char c : s.toCharArray()) sb.append(c).append('#');
sb.append("$");
return sb.toString();
}
// p[i] 记录以 i 为中心的回文半径,核心:
// if (i < R) p[i] = Math.min(R - i, p[2*C - i]); // 利用对称性复用
// 再尝试向两边扩展,更新 C、R