-
Notifications
You must be signed in to change notification settings - Fork 53
/
Copy pathLcsService.php
88 lines (75 loc) · 2.26 KB
/
LcsService.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
<?php
namespace Caxy\HtmlDiff;
use Caxy\HtmlDiff\Strategy\EqualMatchStrategy;
use Caxy\HtmlDiff\Strategy\MatchStrategyInterface;
class LcsService
{
/**
* @var MatchStrategyInterface
*/
protected $matchStrategy;
/**
* LcsService constructor.
*
* @param MatchStrategyInterface $matchStrategy
*/
public function __construct(MatchStrategyInterface $matchStrategy = null)
{
if (null === $matchStrategy) {
$matchStrategy = new EqualMatchStrategy();
}
$this->matchStrategy = $matchStrategy;
}
/**
* @param array $a
* @param array $b
*
* @return array
*/
public function longestCommonSubsequence(array $a, array $b)
{
$c = array();
$m = count($a);
$n = count($b);
for ($i = 0; $i <= $m; $i++) {
$c[$i][0] = 0;
}
for ($j = 0; $j <= $n; $j++) {
$c[0][$j] = 0;
}
for ($i = 1; $i <= $m; $i++) {
for ($j = 1; $j <= $n; $j++) {
if ($this->matchStrategy->isMatch($a[$i - 1], $b[$j - 1])) {
$c[$i][$j] = 1 + (isset($c[$i - 1][$j - 1]) ? $c[$i - 1][$j - 1] : 0);
} else {
$c[$i][$j] = max(
isset($c[$i][$j - 1]) ? $c[$i][$j - 1] : 0,
isset($c[$i - 1][$j]) ? $c[$i - 1][$j] : 0
);
}
}
}
$lcs = array_pad(array(), $m + 1, 0);
$this->compileMatches($c, $a, $b, $m, $n, $lcs);
return $lcs;
}
/**
* @param $c
* @param $a
* @param $b
* @param $i
* @param $j
* @param $matches
*/
protected function compileMatches($c, $a, $b, $i, $j, &$matches)
{
if ($i > 0 && $j > 0 && $this->matchStrategy->isMatch($a[$i - 1], $b[$j - 1])) {
$this->compileMatches($c, $a, $b, $i - 1, $j - 1, $matches);
$matches[$i] = $j;
} elseif ($j > 0 && ($i === 0 || $c[$i][$j - 1] >= $c[$i - 1][$j])) {
$this->compileMatches($c, $a, $b, $i, $j - 1, $matches);
} elseif ($i > 0 && ($j === 0 || $c[$i][$j - 1] < $c[$i - 1][$j])) {
$this->compileMatches($c, $a, $b, $i - 1, $j, $matches);
}
}
}