(function (exports) { 'use strict'; exports.longestIncreasingSubsequence = (function () { /** * Find the index of the first largest element in array. * Complexity: O(N). * * @private * @param {Array} array The array in which the largest * element should be found. * @return {Number} index of the first largest element */ function max(array) { if (!array || !array.length) { return -1; } var maxIdx = 0; for (var i = 1; i < array.length; i += 1) { if (array[maxIdx].distance < array[i].distance) { maxIdx = i; } } return maxIdx; } /** * Default comparison method. * @private */ function asc(a, b) { return a - b; } /** * Creates directed graph from given array. * Each element's neighbours are the elements which can be * after the element in the resulting sequence.

* Complexity: O(N^2). * @private * @param {Array} array The input array. * @param {Function} cmp Comparator. * @return {Object} Graph represented with list of neighbours. */ function buildDag(array, cmp) { var result = []; for (var i = 0; i < array.length; i += 1) { result[i] = []; for (var j = i + 1; j < array.length; j += 1) { if (cmp(array[i], array[j]) < 0) { result[i].push(j); } } } return result; } /** * Finds the longest increasing sub-sequence for given node.

* Complexity: O(N^N). * @private * @param {Object} dag Graph represented with list of neighbours. * @param {number} node The current node. * @return {object} The longest increasing sub-sequence for given node. */ function find(dag, node) { node = node || 0; if (find.memo[node]) { return find.memo[node]; } var neighbours = dag[node]; var neighboursDistance = []; var maxDist; var maxNode; var distance; var result; if (!neighbours.length) { return { distance: 1, neighbour: undefined, node: node }; } for (var i = 0; i < neighbours.length; i += 1) { neighboursDistance[i] = find(dag, neighbours[i]); } maxDist = max(neighboursDistance); maxNode = neighbours[maxDist]; distance = 1 + neighboursDistance[maxDist].distance; find.memo[node] = result = { distance: distance, neighbour: neighboursDistance[maxDist], node: node }; return result; } /** * Algorithm from dynamic programming. It finds the longest * sub-sequence of increasing numbers. It is not required * the numbers to be neighboring. For example for 1, 5, 2 * sequence the longest sub-sequence is 1, 2. * * @example * var subsequence = require('path-to-algorithms/src/searching/'+ * 'longest-increasing-subsequence').longestIncreasingSubsequence; * console.log(subsequence([1, 0, 4, 3, 5])); // 1, 4, 5 * * @public * @module searching/longest-increasing-subsequence * @param {Array} array Input sequence. * @param {Function} cmp Comparator. * @return {Array} Longest increasing subsequence. */ return function (array, cmp) { cmp = cmp || asc; var results = []; var dag = buildDag(array, cmp); var maxPath; find.memo = []; for (var i = 0; i < array.length; i += 1) { results.push(find(dag, i)); } maxPath = results[max(results)]; results = []; while (maxPath) { results.push(array[maxPath.node]); maxPath = maxPath.neighbour; } return results; }; })(); })(typeof window === 'undefined' ? module.exports : window);