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