本文目录导读:

我来详细讲解如何在PHP中实现最大公共子序列(LCS),包含多种方法和完整示例。
动态规划实现(推荐)
这是最经典的实现方式,时间复杂度 O(mn):
<?php
function longestCommonSubsequenceDP($text1, $text2) {
$m = strlen($text1);
$n = strlen($text2);
// 创建DP表
$dp = array_fill(0, $m + 1, array_fill(0, $n + 1, 0));
// 填充DP表
for ($i = 1; $i <= $m; $i++) {
for ($j = 1; $j <= $n; $j++) {
if ($text1[$i - 1] === $text2[$j - 1]) {
$dp[$i][$j] = $dp[$i - 1][$j - 1] + 1;
} else {
$dp[$i][$j] = max($dp[$i - 1][$j], $dp[$i][$j - 1]);
}
}
}
// 回溯找到LCS字符串
$lcs = '';
$i = $m;
$j = $n;
while ($i > 0 && $j > 0) {
if ($text1[$i - 1] === $text2[$j - 1]) {
$lcs = $text1[$i - 1] . $lcs;
$i--;
$j--;
} else if ($dp[$i - 1][$j] > $dp[$i][$j - 1]) {
$i--;
} else {
$j--;
}
}
return [
'length' => $dp[$m][$n],
'sequence' => $lcs
];
}
// 使用示例
$text1 = "ABCDGH";
$text2 = "AEDFHR";
$result = longestCommonSubsequenceDP($text1, $text2);
echo "LCS长度: " . $result['length'] . "\n"; // 输出: 3
echo "LCS序列: " . $result['sequence'] . "\n"; // 输出: ADH
?>
空间优化版本
只保留两行数据,节省内存:
<?php
function longestCommonSubsequenceOptimized($text1, $text2) {
$m = strlen($text1);
$n = strlen($text2);
// 只保留两行
$prev = array_fill(0, $n + 1, 0);
$curr = array_fill(0, $n + 1, 0);
for ($i = 1; $i <= $m; $i++) {
for ($j = 1; $j <= $n; $j++) {
if ($text1[$i - 1] === $text2[$j - 1]) {
$curr[$j] = $prev[$j - 1] + 1;
} else {
$curr[$j] = max($prev[$j], $curr[$j - 1]);
}
}
// 交换数组
list($prev, $curr) = [$curr, $prev];
}
return $prev[$n]; // 只返回长度
}
// 使用示例
$text1 = "AGGTAB";
$text2 = "GXTXAYB";
echo "LCS长度: " . longestCommonSubsequenceOptimized($text1, $text2) . "\n";
// 输出: 4
?>
递归实现(带记忆化)
<?php
function longestCommonSubsequenceRecursive($text1, $text2, $m, $n, &$memo = []) {
// 基本情况
if ($m === 0 || $n === 0) {
return 0;
}
// 检查是否已计算
$key = $m . ',' . $n;
if (isset($memo[$key])) {
return $memo[$key];
}
// 递归计算
if ($text1[$m - 1] === $text2[$n - 1]) {
$memo[$key] = 1 + longestCommonSubsequenceRecursive(
$text1, $text2, $m - 1, $n - 1, $memo
);
} else {
$memo[$key] = max(
longestCommonSubsequenceRecursive($text1, $text2, $m - 1, $n, $memo),
longestCommonSubsequenceRecursive($text1, $text2, $m, $n - 1, $memo)
);
}
return $memo[$key];
}
// 使用示例
$text1 = "ABCBDAB";
$text2 = "BDCAB";
$m = strlen($text1);
$n = strlen($text2);
echo "LCS长度: " . longestCommonSubsequenceRecursive($text1, $text2, $m, $n) . "\n";
// 输出: 4
?>
完整的多子序列实现
返回所有可能的LCS:
<?php
class LCSFinder {
private $dp = [];
private $text1;
private $text2;
public function findAll($text1, $text2) {
$this->text1 = $text1;
$this->text2 = $text2;
$m = strlen($text1);
$n = strlen($text2);
// 构建DP表
$this->buildDP($m, $n);
// 找出所有LCS
$result = $this->backtrackAll($m, $n);
// 去重并返回
return [
'length' => $this->dp[$m][$n],
'sequences' => array_unique($result)
];
}
private function buildDP($m, $n) {
$this->dp = array_fill(0, $m + 1, array_fill(0, $n + 1, 0));
for ($i = 1; $i <= $m; $i++) {
for ($j = 1; $j <= $n; $j++) {
if ($this->text1[$i - 1] === $this->text2[$j - 1]) {
$this->dp[$i][$j] = $this->dp[$i - 1][$j - 1] + 1;
} else {
$this->dp[$i][$j] = max(
$this->dp[$i - 1][$j],
$this->dp[$i][$j - 1]
);
}
}
}
}
private function backtrackAll($i, $j) {
if ($i === 0 || $j === 0) {
return [''];
}
if ($this->text1[$i - 1] === $this->text2[$j - 1]) {
$subSequences = $this->backtrackAll($i - 1, $j - 1);
return array_map(function($seq) use ($i) {
return $seq . $this->text1[$i - 1];
}, $subSequences);
}
$result = [];
if ($this->dp[$i - 1][$j] >= $this->dp[$i][$j - 1]) {
$result = array_merge($result, $this->backtrackAll($i - 1, $j));
}
if ($this->dp[$i][$j - 1] >= $this->dp[$i - 1][$j]) {
$result = array_merge($result, $this->backtrackAll($i, $j - 1));
}
return $result;
}
}
// 使用示例
$finder = new LCSFinder();
$text1 = "ABCBDAB";
$text2 = "BDCAB";
$result = $finder->findAll($text1, $text2);
echo "LCS长度: " . $result['length'] . "\n";
echo "所有LCS序列: \n";
foreach ($result['sequences'] as $seq) {
echo " - " . $seq . "\n";
}
?>
性能测试和比较
<?php
function performanceTest() {
$testCases = [
['A', 'A'],
['ABCD', 'ABCD'],
['ABCD', 'DCBA'],
['AGGTAB', 'GXTXAYB'],
['ABCBDAB', 'BDCAB'],
['ACCGGTCGAGTGCGCGGAAGCCGGCCGAA', 'GTCGTTCGGAATGCCGTTGCTCTGTAAA']
];
foreach ($testCases as $index => $test) {
echo "测试用例 " . ($index + 1) . ":\n";
echo " 字符串1: " . $test[0] . "\n";
echo " 字符串2: " . $test[1] . "\n";
// 方法1: DP完整实现
$start = microtime(true);
$result1 = longestCommonSubsequenceDP($test[0], $test[1]);
$time1 = microtime(true) - $start;
// 方法2: 优化版DP
$start = microtime(true);
$result2 = longestCommonSubsequenceOptimized($test[0], $test[1]);
$time2 = microtime(true) - $start;
echo " 完整DP: 长度={$result1['length']}, 序列='{$result1['sequence']}', 耗时={$time1}\n";
echo " 优化版: 长度={$result2}, 耗时={$time2}\n\n";
}
}
performanceTest();
?>
实际应用示例
<?php
class FileComparer {
public function compareFiles($file1, $file2) {
$content1 = file_get_contents($file1);
$content2 = file_get_contents($file2);
// 按行分割
$lines1 = explode("\n", $content1);
$lines2 = explode("\n", $content2);
// 比较行序列
$result = $this->findLCSLines($lines1, $lines2);
return $result;
}
private function findLCSLines($lines1, $lines2) {
$m = count($lines1);
$n = count($lines2);
$dp = array_fill(0, $m + 1, array_fill(0, $n + 1, 0));
for ($i = 1; $i <= $m; $i++) {
for ($j = 1; $j <= $n; $j++) {
if ($lines1[$i - 1] === $lines2[$j - 1]) {
$dp[$i][$j] = $dp[$i - 1][$j - 1] + 1;
} else {
$dp[$i][$j] = max($dp[$i - 1][$j], $dp[$i][$j - 1]);
}
}
}
// 生成差异报告
$commonLines = [];
$i = $m;
$j = $n;
while ($i > 0 && $j > 0) {
if ($lines1[$i - 1] === $lines2[$j - 1]) {
$commonLines[] = $lines1[$i - 1];
$i--;
$j--;
} else if ($dp[$i - 1][$j] > $dp[$i][$j - 1]) {
$i--;
} else {
$j--;
}
}
return array_reverse($commonLines);
}
}
// 使用示例
$comparer = new FileComparer();
$commonLines = $comparer->compareFiles('file1.txt', 'file2.txt');
echo "共同的行数: " . count($commonLines) . "\n";
echo "共同的内容:\n";
print_r($commonLines);
?>
- 推荐使用动态规划:时间复杂度O(mn),空间复杂度O(mn)
- 内存优化:使用两行数组,空间复杂度降为O(min(m,n))
- 处理大数据:考虑使用文件流和分块处理
- 实际应用:文件比较、DNA序列分析、文本差异对比等
选择哪种实现取决于你的具体需求:
- 只需要长度:使用空间优化版本
- 需要具体序列:使用完整DP版本
- 需要所有可能序列:使用回溯版本
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播