From 69a833f56ddf25ea83eab88194ad54e0c620c8ed Mon Sep 17 00:00:00 2001 From: dirb Date: Sun, 19 Feb 2017 20:42:30 -0600 Subject: [PATCH 1/2] src/filters/lcs.js: implement backtrack in a iterative way --- src/filters/lcs.js | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/src/filters/lcs.js b/src/filters/lcs.js index 70d5b349..2e18b0af 100644 --- a/src/filters/lcs.js +++ b/src/filters/lcs.js @@ -37,34 +37,37 @@ var lengthMatrix = function(array1, array2, match, context) { return matrix; }; -var backtrack = function(matrix, array1, array2, index1, index2, context) { - if (index1 === 0 || index2 === 0) { - return { - sequence: [], - indices1: [], - indices2: [] - }; - } +var backtrack = function(matrix, array1, array2, context) { + var index1 = array1.length; + var index2 = array2.length; - if (matrix.match(array1, array2, index1 - 1, index2 - 1, context)) { - var subsequence = backtrack(matrix, array1, array2, index1 - 1, index2 - 1, context); - subsequence.sequence.push(array1[index1 - 1]); - subsequence.indices1.push(index1 - 1); - subsequence.indices2.push(index2 - 1); - return subsequence; - } + var subsequence = { + sequence: [], + indices1: [], + indices2: [] + }; - if (matrix[index1][index2 - 1] > matrix[index1 - 1][index2]) { - return backtrack(matrix, array1, array2, index1, index2 - 1, context); - } else { - return backtrack(matrix, array1, array2, index1 - 1, index2, context); + while (0 < index1 && 0 < index2) { + if (matrix.match(array1, array2, index1-1, index2-1, context)) { + subsequence.sequence.push(array1[index1-1]); + subsequence.indices1.push(index1-1); + subsequence.indices2.push(index2-1); + index1--; + index2--; + } else if (matrix[index1][index2-1] > matrix[index1-1][index2]) { + index2--; + } else { + index1--; + } } + + return subsequence; }; var get = function(array1, array2, match, context) { context = context || {}; var matrix = lengthMatrix(array1, array2, match || defaultMatch, context); - var result = backtrack(matrix, array1, array2, array1.length, array2.length, context); + var result = backtrack(matrix, array1, array2, context); if (typeof array1 === 'string' && typeof array2 === 'string') { result.sequence = result.sequence.join(''); } From efe391171a5cac63f70d89136462b5cdf90e9a83 Mon Sep 17 00:00:00 2001 From: dirb Date: Sat, 25 Feb 2017 19:24:29 -0600 Subject: [PATCH 2/2] src/filters/lcs.js: optimize by trim off matching items at the beginning and the end --- src/filters/lcs.js | 55 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/src/filters/lcs.js b/src/filters/lcs.js index 2e18b0af..4f88862c 100644 --- a/src/filters/lcs.js +++ b/src/filters/lcs.js @@ -11,8 +11,23 @@ var defaultMatch = function(array1, array2, index1, index2) { }; var lengthMatrix = function(array1, array2, match, context) { - var len1 = array1.length; - var len2 = array2.length; + var start = 0; + var end1 = array1.length; + var end2 = array2.length; + + //trim off the matching items at the beginning + while (start < end1 && start < end2 && match(array1, array2, start, start, context)) { + start++; + } + + //trim off the matching items at the end + while (start < end1 && start < end2 && match(array1, array2, end1 - 1, end2 - 1, context)) { + end1--; + end2--; + } + + var len1 = end1 - start; + var len2 = end2 - start; var x, y; // initialize empty matrix of len1+1 x len2+1 @@ -24,10 +39,13 @@ var lengthMatrix = function(array1, array2, match, context) { } } matrix.match = match; + matrix.start = start; + matrix.end1 = end1; + matrix.end2 = end2; // save sequence lengths for each coordinate for (x = 1; x < len1 + 1; x++) { for (y = 1; y < len2 + 1; y++) { - if (match(array1, array2, x - 1, y - 1, context)) { + if (match(array1, array2, start + x - 1, start + y - 1, context)) { matrix[x][y] = matrix[x - 1][y - 1] + 1; } else { matrix[x][y] = Math.max(matrix[x - 1][y], matrix[x][y - 1]); @@ -38,23 +56,38 @@ var lengthMatrix = function(array1, array2, match, context) { }; var backtrack = function(matrix, array1, array2, context) { - var index1 = array1.length; - var index2 = array2.length; - var subsequence = { sequence: [], indices1: [], indices2: [] }; + var x; + //push matching items at the beginning + for (x = 0; x < matrix.start; x++) { + subsequence.sequence.push(array1[x]); + subsequence.indices1.push(x); + subsequence.indices2.push(x); + } + + //push matching items at the end + for (x = matrix.end1; x < array1.length; x++) { + subsequence.sequence.push(array1[x]); + subsequence.indices1.push(x); + subsequence.indices2.push(matrix.end2 + (x - matrix.end1)); + } + + var index1 = matrix.end1 - matrix.start; + var index2 = matrix.end2 - matrix.start; + while (0 < index1 && 0 < index2) { - if (matrix.match(array1, array2, index1-1, index2-1, context)) { - subsequence.sequence.push(array1[index1-1]); - subsequence.indices1.push(index1-1); - subsequence.indices2.push(index2-1); + if (matrix.match(array1, array2, matrix.start + index1 - 1, matrix.start + index2 - 1, context)) { + subsequence.sequence.push(array1[matrix.start + index1 - 1]); + subsequence.indices1.push(matrix.start + index1 - 1); + subsequence.indices2.push(matrix.start + index2 - 1); index1--; index2--; - } else if (matrix[index1][index2-1] > matrix[index1-1][index2]) { + } else if (matrix[index1][index2 - 1] > matrix[index1 - 1][index2]) { index2--; } else { index1--;