searching/longest-common-subsequence.js

  1. (function (exports) {
  2. 'use strict';
  3. exports.longestCommonSubsequence = (function () {
  4. /**
  5. * Find the lengths of longest common sub-sequences
  6. * of two strings and their substrings.
  7. *
  8. * Complexity: O(MN).
  9. *
  10. * @private
  11. * @param {String} first string
  12. * @param {String} second string
  13. * @return {Array} two dimensional array with LCS
  14. * lengths of input strings and their substrings.
  15. *
  16. */
  17. function getLcsLengths(str1, str2) {
  18. var result = [];
  19. for (var i = -1; i < str1.length; i = i + 1) {
  20. result[i] = [];
  21. for (var j = -1; j < str2.length; j = j + 1) {
  22. if (i === -1 || j === -1) {
  23. result[i][j] = 0;
  24. } else if (str1[i] === str2[j]) {
  25. result[i][j] = result[i - 1][j - 1] + 1;
  26. } else {
  27. result[i][j] = Math.max(result[i - 1][j], result[i][j - 1]);
  28. }
  29. }
  30. }
  31. return result;
  32. }
  33. /**
  34. * Find longest common sub-sequences of two strings.
  35. *
  36. * Complexity: O(M + N).
  37. *
  38. * @private
  39. * @param {String} first string
  40. * @param {String} second string
  41. * @return {Array} two dimensional array with LCS
  42. * lengths of input strings and their substrings
  43. * returned from 'getLcsLengths' function.
  44. *
  45. */
  46. function getLcs(str1, str2, lcsLengthsMatrix) {
  47. var execute = function (i, j) {
  48. if (!lcsLengthsMatrix[i][j]) {
  49. return '';
  50. } else if (str1[i] === str2[j]) {
  51. return execute(i - 1, j - 1) + str1[i];
  52. } else if (lcsLengthsMatrix[i][j - 1] > lcsLengthsMatrix[i - 1][j]) {
  53. return execute(i, j - 1);
  54. } else {
  55. return execute(i - 1, j);
  56. }
  57. };
  58. return execute(str1.length - 1, str2.length - 1);
  59. }
  60. /**
  61. * Algorithm from dynamic programming. It finds the longest
  62. * common sub-sequence of two strings. For example for strings 'abcd'
  63. * and 'axxcda' the longest common sub-sequence is 'acd'.
  64. *
  65. * @example
  66. * var subsequence = require('path-to-algorithms/src/searching/'+
  67. * 'longest-common-subsequence').longestCommonSubsequence;
  68. * console.log(subsequence('abcd', 'axxcda'); // 'acd'
  69. *
  70. * @public
  71. * @module searching/longest-common-subsequence
  72. * @param {String} first input string.
  73. * @param {String} second input string.
  74. * @return {Array} Longest common subsequence.
  75. */
  76. return function (str1, str2) {
  77. var lcsLengthsMatrix = getLcsLengths(str1, str2);
  78. return getLcs(str1, str2, lcsLengthsMatrix);
  79. };
  80. })();
  81. })(typeof window === 'undefined' ? module.exports : window);