Skip to content

Commit 626eb8a

Browse files
committedApr 26, 2018
Add longest increasing subsequence.
1 parent 15e798c commit 626eb8a

File tree

4 files changed

+137
-2
lines changed

4 files changed

+137
-2
lines changed
 

‎README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
* [Combinations](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/combinations) (with and without repetitions)
4141
* [Fisher–Yates Shuffle](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/fisher-yates) - random permutation of a finite sequence
4242
* [Longest Common Subsequence](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/longest-common-subsequnce) (LCS)
43+
* [Longest Increasing subsequence](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/longest-increasing-subsequence)
4344
* **String**
4445
* [Levenshtein Distance](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/levenshtein-distance) - minimum edit distance between two sequences
4546
* [Hamming Distance](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/hamming-distance) - number of positions at which the symbols are different
@@ -92,8 +93,7 @@
9293
* [Levenshtein Distance](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/levenshtein-distance) - minimum edit distance between two sequences
9394
* [Longest Common Subsequence](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/longest-common-subsequnce) (LCS)
9495
* [Longest Common Substring](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/string/longest-common-substring)
95-
* Increasing subsequence
96-
* Longest Increasing subsequence
96+
* [Longest Increasing subsequence](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/sets/longest-increasing-subsequence)
9797
* Shortest common supersequence
9898
* Knapsack problem
9999
* Maximum subarray
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Longest Increasing Subsequence
2+
3+
The longest increasing subsequence problem is to find a subsequence of a
4+
given sequence in which the subsequence's elements are in sorted order,
5+
lowest to highest, and in which the subsequence is as long as possible.
6+
This subsequence is not necessarily contiguous, or unique.
7+
8+
## Complexity
9+
10+
The longest increasing subsequence problem is solvable in
11+
time `O(n log n)`, where `n` denotes the length of the input sequence.
12+
13+
Dynamic programming approach has complexity `O(n * n)`.
14+
15+
## Example
16+
17+
In the first 16 terms of the binary Van der Corput sequence
18+
19+
```
20+
0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15
21+
```
22+
23+
a longest increasing subsequence is
24+
25+
```
26+
0, 2, 6, 9, 11, 15.
27+
```
28+
29+
This subsequence has length six;
30+
the input sequence has no seven-member increasing subsequences.
31+
The longest increasing subsequence in this example is not unique: for
32+
instance,
33+
34+
```
35+
0, 4, 6, 9, 11, 15 or
36+
0, 2, 6, 9, 13, 15 or
37+
0, 4, 6, 9, 13, 15
38+
```
39+
40+
are other increasing subsequences of equal length in the same
41+
input sequence.
42+
43+
## References
44+
45+
- [Wikipedia](https://en.wikipedia.org/wiki/Longest_increasing_subsequence)
46+
- [Dynamic Programming Approach on YouTube](https://www.youtube.com/watch?v=CE2b_-XfVDk)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import dpLongestIncreasingSubsequence from '../dpLongestIncreasingSubsequence';
2+
3+
describe('dpLongestIncreasingSubsequence', () => {
4+
it('should find longest increasing subsequence length', () => {
5+
// Should be:
6+
// 9 or
7+
// 8 or
8+
// 7 or
9+
// 6 or
10+
// ...
11+
expect(dpLongestIncreasingSubsequence([
12+
9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
13+
])).toBe(1);
14+
15+
// Should be:
16+
// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
17+
expect(dpLongestIncreasingSubsequence([
18+
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
19+
])).toBe(10);
20+
21+
// Should be:
22+
// -1, 0, 2, 3
23+
expect(dpLongestIncreasingSubsequence([
24+
3, 4, -1, 0, 6, 2, 3,
25+
])).toBe(4);
26+
27+
// Should be:
28+
// 0, 2, 6, 9, 11, 15 or
29+
// 0, 4, 6, 9, 11, 15 or
30+
// 0, 2, 6, 9, 13, 15 or
31+
// 0, 4, 6, 9, 13, 15
32+
expect(dpLongestIncreasingSubsequence([
33+
0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15,
34+
])).toBe(6);
35+
});
36+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/**
2+
* Dynamic programming approach to find longest increasing subsequence.
3+
* Complexity: O(n * n)
4+
*
5+
* @param {number[]} sequence
6+
* @return {number}
7+
*/
8+
export default function dpLongestIncreasingSubsequence(sequence) {
9+
// Create array with longest increasing substrings length and
10+
// fill it with 1-s that would mean that each element of the sequence
11+
// is itself a minimum increasing subsequence.
12+
const lengthsArray = Array(sequence.length).fill(1);
13+
14+
let previousElementIndex = 0;
15+
let currentElementIndex = 1;
16+
17+
while (currentElementIndex < sequence.length) {
18+
if (sequence[previousElementIndex] < sequence[currentElementIndex]) {
19+
// If current element is bigger then the previous one then
20+
// current element is a part of increasing subsequence which
21+
// length is by one bigger then the length of increasing subsequence
22+
// for previous element.
23+
const newLength = lengthsArray[previousElementIndex] + 1;
24+
if (newLength > lengthsArray[currentElementIndex]) {
25+
// Increase only if previous element would give us bigger subsequence length
26+
// then we already have for current element.
27+
lengthsArray[currentElementIndex] = newLength;
28+
}
29+
}
30+
31+
// Move previous element index right.
32+
previousElementIndex += 1;
33+
34+
// If previous element index equals to current element index then
35+
// shift current element right and reset previous element index to zero.
36+
if (previousElementIndex === currentElementIndex) {
37+
currentElementIndex += 1;
38+
previousElementIndex = 0;
39+
}
40+
}
41+
42+
// Find the biggest element in lengthsArray.
43+
// This number is the biggest length of increasing subsequence.
44+
let longestIncreasingLength = 0;
45+
46+
for (let i = 0; i < lengthsArray.length; i += 1) {
47+
if (lengthsArray[i] > longestIncreasingLength) {
48+
longestIncreasingLength = lengthsArray[i];
49+
}
50+
}
51+
52+
return longestIncreasingLength;
53+
}

0 commit comments

Comments
 (0)
Please sign in to comment.