PHP 字符串最长公共子串

5次阅读

最长公共子串是连续、相同且长度最大的子串,推荐动态规划解法:用dpi表示以str1[i-1]和str2[j-1]结尾的公共子串长度,字符相等时dpi=dpi-1+1,否则为0,同时记录最大长度和结束位置,最后截取返回。

PHP 字符串最长公共子串

php 中求两个字符串的最长公共子串(Longest Common Substring),核心是找**连续、相同、长度最大**的子串,不是子序列(不要求字符位置连续)。最常用且高效的方法是动态规划,时间复杂度 O(m×n),空间可优化至 O(min(m,n))。

动态规划解法(推荐)

用二维数组 $dp[i][j] 表示以 $str1[i-1]$str2[j-1] 结尾的公共子串长度。若字符相等,则 $dp[i][j] = $dp[i-1][j-1] + 1;否则为 0。过程中记录最大长度和结束位置,最后截取即可。

  • 初始化二维数组(或滚动数组优化空间)
  • 遍历两字符串所有字符组合,更新 dp 值并维护 max_len 和 end_pos
  • 根据 end_pos 和 max_len 从原字符串中提取子串

代码实现(带注释)

// 示例:返回最长公共子串,多个等长时返回第一个

function longestCommonSubstring($str1, $str2) {     if (empty($str1) || empty($str2)) return ''; <pre class="brush:php;toolbar:false;">$len1 = strlen($str1); $len2 = strlen($str2); $dp = array_fill(0, $len1 + 1, array_fill(0, $len2 + 1, 0)); $maxLen = 0; $endPos = 0; // 在 str1 中的结束索引(0-based)  for ($i = 1; $i <= $len1; $i++) {     for ($j = 1; $j <= $len2; $j++) {         if ($str1[$i-1] === $str2[$j-1]) {             $dp[$i][$j] = $dp[$i-1][$j-1] + 1;             if ($dp[$i][$j] > $maxLen) {                 $maxLen = $dp[$i][$j];                 $endPos = $i - 1;             }         } else {             $dp[$i][$j] = 0;         }     } }  return $maxLen ? substr($str1, $endPos - $maxLen + 1, $maxLen) : '';

}

立即学习PHP免费学习笔记(深入)”;

// 使用示例 echo longestCommonSubstring(“abcdef”, “zabcf”); // 输出: “ab”

注意事项与边界情况

算法区分大小写,空字符串返回空,完全无公共字符时返回空字符串。若需忽略大小写,可提前用 strtolower() 统一处理。注意 PHP 字符串下标是字节级的,对 UTF-8 多字节字符需改用 mb_* 函数(如 mb_substr、mb_strlen)并指定编码,否则中文等可能截断乱码。

  • ASCII 场景直接用 strlen/substr 即可
  • 含中文、emoji 等 UTF-8 字符 → 改用 mb_strlen、mb_substr,并在 dp 中用 mb_substr($str, $i, 1) 比较字符
  • 只需求长度不关心内容?可省略 endPos 记录,仅维护 maxLen

简单暴力法(仅适合极短字符串)

枚举 str1 的所有子串(O(n²)),用 strpos 或 strstr 判断是否在 str2 中出现(O(m)),总复杂度 O(n²m),不推荐用于长度超 100 的字符串。

text=ZqhQzanResources