diff --git a/.gitignore b/.gitignore index 690b01c..c0d4695 100644 --- a/.gitignore +++ b/.gitignore @@ -59,3 +59,6 @@ typings/ # Transpiled files lib/ + +# IDE +.idea/ diff --git a/package.json b/package.json index 667e41c..c0a9f2c 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "scripts": { "lint": "eslint src/**/*.js", "test": "jest --coverage", + "test-single": "jest --coverage longest-common-substring.spec.js", "test-debug": "BABEL_ENV=dev node --inspect ./node_modules/.bin/jest --runInBand", "build": "eslint src/**/*.js && jest --coverage && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && babel src --out-dir lib --ignore spec.js" }, diff --git a/src/longest-common-substring.js b/src/longest-common-substring.js index f834d30..8050e0c 100644 --- a/src/longest-common-substring.js +++ b/src/longest-common-substring.js @@ -5,7 +5,7 @@ * are concatenated with unique markers and their positions recorded in a * string index map. Iterating over the heights given in the longest common * prefix array, the string index map is used to lookup whet substring each - * suffix array enry belongs to. If k substrings are seen at the same height, + * suffix array entry belongs to. If k substrings are seen at the same height, * then a common substring across all given substrings has been found. * * Copyright (C) 2017 Kim Burgaard @@ -288,32 +288,18 @@ export default function longestCommonSubstring(strings, indexMap = 'log') { const h = lcp[i]; const suffixNext = sa[i + 1]; const stringIndexNext = stringIndexMap.lookup(suffixNext); - let j = 0; - if (h >= top && h > 0) { - // add a stack entry for each height level and map the string index to its suffix and length - while (j < h) { - if (j >= entryStack.length) { - entryStack[j] = {}; - } - entryStack[j][stringIndex] = [suffix, j + 1]; - entryStack[j][stringIndexNext] = [suffixNext, j + 1]; - j++; - } - top = j; - } // if the height goes down, then check what we have on the stack - j = top; - while (j > h) { + while (top > h) { const entries = entryStack.pop(); - if (j >= longest) { + if (top >= longest) { const keys = Object.keys(entries); // check if all k strings have been seen if (keys.length === k) { const r = entries[keys[0]]; - if (j > longest) { + if (top > longest) { // reset result for the longest substring seen so far - longest = j; + longest = top; result = [r]; } else { // add substring to its peers of longest substrings seen so far @@ -321,10 +307,23 @@ export default function longestCommonSubstring(strings, indexMap = 'log') { } } } - j--; + top--; + } + + let j = 0; + if (h >= top && h > 0) { + // add a stack entry for each height level and map the string index to its suffix and length + while (j < h) { + if (j >= entryStack.length) { + entryStack[j] = {}; + } + entryStack[j][stringIndex] = [suffix, j + 1]; + entryStack[j][stringIndexNext] = [suffixNext, j + 1]; + j++; + } + top = j; } - top = h; i++; suffix = suffixNext; stringIndex = stringIndexNext; diff --git a/src/longest-common-substring.spec.js b/src/longest-common-substring.spec.js index b2c29ca..fe270b9 100644 --- a/src/longest-common-substring.spec.js +++ b/src/longest-common-substring.spec.js @@ -340,6 +340,16 @@ describe('longestCommonSubstring', () => { expect(result).toEqual([]); }); + it('supports use cases related to issue #1', () => { + const result1 = longestCommonSubstring(['abc - 48h', 'abc - 108h', 'abc - 168h']); + const result2 = longestCommonSubstring(['abcTab', 'abcUab', 'abcTab']); + const result3 = longestCommonSubstring(['abcTde', 'abcUde', 'abcTde']); + + expect(result1).toEqual(['abc - ']); + expect(result2).toEqual(['abc']); + expect(result3).toEqual(['abc']); + }); + it('throws an error when given a boolean', () => { expect(() => longestCommonSubstring(true)).toThrow(); expect(() => longestCommonSubstring(false)).toThrow();