Add an LCS implementation.

This commit is contained in:
Natalie Weizenbaum 2016-08-02 11:36:34 -07:00
parent ab2d8ae3f3
commit efaf64020f

View File

@ -97,3 +97,40 @@ SimpleSelector unifyUniversalAndElement(SimpleSelector selector1,
: new TypeSelector(
new NamespacedIdentifier(name, namespace: namespace));
}
List/*<T>*/ longestCommonSubsequence/*<T>*/(List/*<T>*/ list1,
List/*<T>*/ list2, {/*=T*/ select(/*=T*/ element1, /*=T*/ element2)}) {
select ??= (element1, element2) => element1 == element2 ? element1 : null;
var lengths = new List.generate(
list1.length + 1, (_) => new List.filled(list2.length + 1, 0),
growable: false);
var selections = new List.generate(
list1.length, (_) => new List/*<T>*/(list2.length),
growable: false);
// TODO(nweiz): Calling [select] here may be expensive. Can we use a memoizing
// approach to avoid calling it O(n*m) times in most cases?
for (var i = 0; i < list1.length; i++) {
for (var j = 0; j < list2.length; j++) {
var selection = select(list1[i], list2[j]);
selections[i][j] = selection;
lengths[i + 1][j + 1] = selection == null
? math.max(lengths[i + 1][j], lengths[i][j + 1])
: lengths[i][j] + 1;
}
}
List/*<T>*/ backtrack(int i, int j) {
if (i == -1 || j == -1) return [];
var selection = selections[i][j];
if (selection != null) return backtrack(i - 1, j - 1)..add(selection);
return lengths[i + 1][j] > lengths[i][j + 1]
? backtrack(i, j - 1)
: backtrack(i - 1, j);
}
return backtrack(list1.length - 1, list2.length - 1);
}