mirror of
https://github.moeyy.xyz/https://github.com/trekhleb/javascript-algorithms.git
synced 2024-11-10 11:09:43 +08:00
Merge f09c41a467
into ca3d16dcce
This commit is contained in:
commit
8f8cc2b0e6
@ -1,53 +1,41 @@
|
|||||||
/**
|
/**
|
||||||
* Dynamic programming approach to find longest increasing subsequence.
|
* Optimized approach to find longest increasing subsequence.
|
||||||
* Complexity: O(n * n)
|
* Complexity: O(n * log n)
|
||||||
*
|
*
|
||||||
* @param {number[]} sequence
|
* @param {number[]} sequence
|
||||||
* @return {number}
|
* @return {number}
|
||||||
*/
|
*/
|
||||||
export default function dpLongestIncreasingSubsequence(sequence) {
|
export default function dpLongestIncreasingSubsequence(sequence) {
|
||||||
// Create array with longest increasing substrings length and
|
if (sequence.length === 0) {
|
||||||
// fill it with 1-s that would mean that each element of the sequence
|
return 0;
|
||||||
// is itself a minimum increasing subsequence.
|
}
|
||||||
const lengthsArray = Array(sequence.length).fill(1);
|
|
||||||
|
|
||||||
let previousElementIndex = 0;
|
// This will store the smallest tail value for all increasing subsequences
|
||||||
let currentElementIndex = 1;
|
// with length i+1 in tail[i].
|
||||||
|
const tails = [];
|
||||||
|
|
||||||
while (currentElementIndex < sequence.length) {
|
sequence.forEach((num) => {
|
||||||
if (sequence[previousElementIndex] < sequence[currentElementIndex]) {
|
let left = 0;
|
||||||
// If current element is bigger then the previous one then
|
let right = tails.length;
|
||||||
// current element is a part of increasing subsequence which
|
|
||||||
// length is by one bigger then the length of increasing subsequence
|
// Binary search for the insertion point of the current element.
|
||||||
// for previous element.
|
while (left < right) {
|
||||||
const newLength = lengthsArray[previousElementIndex] + 1;
|
const mid = Math.floor((left + right) / 2);
|
||||||
if (newLength > lengthsArray[currentElementIndex]) {
|
if (tails[mid] < num) {
|
||||||
// Increase only if previous element would give us bigger subsequence length
|
left = mid + 1;
|
||||||
// then we already have for current element.
|
} else {
|
||||||
lengthsArray[currentElementIndex] = newLength;
|
right = mid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move previous element index right.
|
// If left is equal to the length of tails, it means we are adding a new subsequence.
|
||||||
previousElementIndex += 1;
|
if (left === tails.length) {
|
||||||
|
tails.push(num);
|
||||||
// If previous element index equals to current element index then
|
} else {
|
||||||
// shift current element right and reset previous element index to zero.
|
// Otherwise, we are updating an existing subsequence with a new tail value.
|
||||||
if (previousElementIndex === currentElementIndex) {
|
tails[left] = num;
|
||||||
currentElementIndex += 1;
|
|
||||||
previousElementIndex = 0;
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
// Find the biggest element in lengthsArray.
|
return tails.length;
|
||||||
// This number is the biggest length of increasing subsequence.
|
|
||||||
let longestIncreasingLength = 0;
|
|
||||||
|
|
||||||
for (let i = 0; i < lengthsArray.length; i += 1) {
|
|
||||||
if (lengthsArray[i] > longestIncreasingLength) {
|
|
||||||
longestIncreasingLength = lengthsArray[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return longestIncreasingLength;
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user