最长公共子串是指多个字符串共有的最长连续子序列;PHP中可通过两两求解、逐步收缩法实现,先取首字符串所有子串为候选,再逐个与后续字符串匹配筛选,最终返回最长者。

PHP 中没有直接叫“最小公共子串”的标准算法,通常大家指的是最短公共子串(Shortest Common Superstring, SCS)或更常见的最长公共子串(Longest Common Substring)。但“最小公共子串”这个说法容易歧义——如果指多个字符串共有的、长度最短的非空子串,那只要存在公共子串,最短一定是长度为 1 的字符(比如都含 'a'),意义不大。
实际开发中,真正有用且常被需要的是:多个字符串的最长公共子串(LCSs),即所有输入字符串都包含的、长度最长的连续子序列(子串)。下面以该问题为核心,给出 PHP 实现方案。
什么是“最长公共子串”
给定字符串数组,如 ['ababc', 'abcd', 'abdc'],它们的公共子串有 'a'、'ab'、'b' 等,其中最长的是 'ab'(长度 2)。注意区别于“最长公共子序列(LCS)”,子串要求连续。
两两求解 + 逐步收缩法(推荐,简洁可靠)
思路:先求前两个字符串的最长公共子串,再用结果与第三个比,依此类推。每次迭代只保留当前所有字符串共有的最长子串候选集,最后返回最长的那个。
立即学习“PHP免费学习笔记(深入)”;
- 先写一个辅助函数
longestCommonSubstringOfTwo($s1, $s2),暴力枚举 $s1 的所有子串,检查是否在 $s2 中出现,记录最长的 - 主函数遍历字符串数组,逐个合并公共子串集合(取交集),并动态更新最长结果
- 时间复杂度可控,适合中小规模数据(如几十个字符串,每个几百字符)
代码实现(含注释)
// 示例:支持任意数量字符串的最长公共子串
<?php
function longestCommonSubstring(array $strings): string {
if (empty($strings)) return '';
if (count($strings) === 1) return $strings[0];
<pre class="brush:php;toolbar:false;">// 辅助函数:求两个字符串的最长公共子串
$lcsTwo = function(string $a, string $b): array {
$lenA = strlen($a);
$lenB = strlen($b);
$maxLen = 0;
$result = [];
for ($i = 0; $i < $lenA; $i++) {
for ($j = 0; $j < $lenB; $j++) {
$k = 0;
while ($i + $k < $lenA && $j + $k < $lenB && $a[$i + $k] === $b[$j + $k]) {
$k++;
}
if ($k > $maxLen) {
$maxLen = $k;
$result = [$a(substr($a, $i, $k))];
} elseif ($k === $maxLen && $k > 0) {
$substr = substr($a, $i, $k);
if (!in_array($substr, $result)) {
$result[] = $substr;
}
}
}
}
return $result;
};
// 从第一个字符串开始,逐步与后续字符串求公共子串
$common = str_split($strings[0]); // 初始候选:所有单字符
foreach (array_slice($strings, 1) as $str) {
$newCommon = [];
foreach ($common as $substr) {
// 检查当前候选是否在新字符串中存在
if (strpos($str, $substr) !== false) {
$newCommon[] = $substr;
}
}
if (empty($newCommon)) return '';
$common = $newCommon;
}
// 在最终候选中找最长的(可去重)
usort($common, function($a, $b) { return strlen($b) - strlen($a); });
return $common ? $common[0] : '';}
// 测试 $test = ['ababc', 'abcd', 'abdc']; echo longestCommonSubstring($test); // 输出: "ab" ?>
优化建议(大数据场景)
若字符串很长(如 >10KB)或数量很多(>100),暴力法变慢。可考虑:
- 先对字符串按长度排序,从最短的开始作为基准,减少子串枚举量
- 使用后缀数组(Suffix Array)或广义后缀自动机(Generalized Suffix Automaton),但 PHP 原生不支持,需扩展或调用外部工具
- 对大小写、空白等预处理统一(如 trim + strtolower),避免语义相同却被判不同











