給定 N 條字串,找出在所有字串中都出現的最長子串。特殊條件:子串的反向字串若也在所有字串中出現,同樣視為合法。輸出最大長度。
s(候選子串必來自此字串)。s 的所有子串 sub。sub,檢查:subsubimport java.util.Scanner;
public class HDU1238 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int T = sc.nextInt();
while (T-- > 0) {
int n = sc.nextInt();
String[] str = new String[n];
String[] rev = new String[n];
// 讀入並預計算反向字串
for (int i = 0; i < n; i++) {
str[i] = sc.next();
rev[i] = new StringBuilder(str[i]).reverse().toString();
}
// 找最短字串
String shortest = str[0];
for (int i = 1; i < n; i++)
if (str[i].length() < shortest.length()) shortest = str[i];
// 計算最長公共子串長度
int ans = getMaxLen(shortest, str, rev);
System.out.println(ans);
}
}
private static int getMaxLen(String s, String[] str, String[] rev) {
int maxLen = 0;
int L = s.length();
// 枚舉所有子串 s[i..j)
for (int i = 0; i < L; i++) {
for (int j = i + 1; j <= L; j++) {
String sub = s.substring(i, j);
// 剪枝:子串長度不超過當前最大值則跳過
if (sub.length() <= maxLen) continue;
boolean ok = true;
// 正向檢查
for (String x : str) if (!x.contains(sub)) { ok = false; break; }
if (ok) { maxLen = sub.length(); continue; }
// 反向檢查
ok = true;
for (String x : rev) if (!x.contains(sub)) { ok = false; break; }
if (ok) maxLen = sub.length();
}
}
return maxLen;
}
}
若字串長度較大(> 1000),可改用後綴自動機 (SAM)或二分長度 + 雙向哈希將複雜度降至 O(N · L log L)。本題資料範圍下暴力枚舉配合剪枝即可通過。