diff --git a/src/algorithms/sets/longest-increasing-subsequence/dpLongestIncreasingSubsequence.js b/src/algorithms/sets/longest-increasing-subsequence/dpLongestIncreasingSubsequence.js
index e5f2ec6dbf..55fbd4dc11 100644
--- a/src/algorithms/sets/longest-increasing-subsequence/dpLongestIncreasingSubsequence.js
+++ b/src/algorithms/sets/longest-increasing-subsequence/dpLongestIncreasingSubsequence.js
@@ -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);
-
-  let previousElementIndex = 0;
-  let currentElementIndex = 1;
+  if (sequence.length === 0) {
+    return 0;
+  }
 
-  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;
-      }
-    }
+  // This will store the smallest tail value for all increasing subsequences
+  // with length i+1 in tail[i].
+  const tails = [];
 
-    // Move previous element index right.
-    previousElementIndex += 1;
+  sequence.forEach((num) => {
+    let left = 0;
+    let right = tails.length;
 
-    // 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;
+    // 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;
+      }
     }
-  }
 
-  // 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];
+    // 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;
     }
-  }
+  });
 
-  return longestIncreasingLength;
+  return tails.length;
 }