Skip to content

Longest Increasing Subsequence

Given an integer array nums, return the length of the longest strictly increasing subsequence.

A subsequence is a sequence that can be derived from an array by deleting some or no elements without changing the order of the remaining elements.

numsOutputExplanation
[10,9,2,5,3,7,101,18]4The longest increasing subsequence is [2,3,7,101] with length 4
[0,1,0,4,4,4,3,2,1]2The longest increasing subsequence is [0,1] or [0,4] with length 2
[3,1,4,1,5,9,2,6,5,3,5]4One possible LIS: [1,4,5,9] or [1,2,5,9] or [1,2,3,5]
  • 1 <= nums.length <= 2500
  • -10^4 <= nums[i] <= 10^4
ApproachTimeSpaceBest For
DPO(n²)O(n)Easier to understand and code
Binary SearchO(n log n)O(n)Large arrays, optimal complexity
  • Pick DP if you want the foundational approach and clearer logic.
  • Pick Binary Search if you want optimal complexity and algorithmic sophistication.
Clearer Logic
DP
O(n²) time · O(n) space
Optimal Complexity
Binary Search
O(n log n) time · O(n) space
★ Recommended

dp[i] = length of the longest increasing subsequence ending at index i.

For each i, check all previous indices j where nums[j] < nums[i], and extend the best LIS found.

⏱ Time O(n²) Nested loops 💾 Space O(n) DP array
function lisDP(nums):
n = len(nums)
dp = array of size n, all initialized to 1
for i from 1 to n - 1:
for j from 0 to i - 1:
if nums[j] < nums[i]:
dp[i] = max(dp[i], dp[j] + 1)
return max(dp)
longest_increasing_subsequence_dp_n2.py
from typing import List
def longest_increasing_subsequence_dp(nums: List[int]) -> int:
"""
Find length of longest increasing subsequence using DP O(n²).
Time Complexity: O(n²)
Space Complexity: O(n)
dp[i] = length of LIS ending at index i
For each i, check all j < i where nums[j] < nums[i]
dp[i] = max(dp[j]) + 1 for all valid j, or 1 if no such j exists
"""
if not nums:
return 0
n = len(nums)
dp = [1] * n # Each element is a LIS of length 1
for i in range(1, n):
for j in range(i):
if nums[j] < nums[i]:
dp[i] = max(dp[i], dp[j] + 1)
return max(dp)
if __name__ == "__main__":
print(longest_increasing_subsequence_dp([10, 9, 2, 5, 3, 7, 101, 18])) # 4
print(longest_increasing_subsequence_dp([0, 1, 0, 4, 4, 4, 3, 2, 1])) # 2
print(longest_increasing_subsequence_dp([3, 1, 4, 1, 5, 9, 2, 6])) # 4
🎯 Interview Favourite

Maintain a tails array where tails[i] is the smallest tail element of all LIS of length i+1.

For each number, use binary search to find its position in tails. If the position is at the end, we extend the longest LIS; otherwise, we update the tail to possibly get a better LIS.

⏱ Time O(n log n) Binary search per element 💾 Space O(n) Tails array

The tails array maintains the invariant that tails is strictly increasing and sorted. At any point, tails[i] contains the smallest possible tail value for an LIS of length i+1. This allows us to use binary search to efficiently find where a new number fits.

function lisBinarySearch(nums):
tails = empty array
for num in nums:
pos = binary_search_left(tails, num)
if pos == len(tails):
tails.append(num)
else:
tails[pos] = num
return len(tails)
longest_increasing_subsequence_bs.py
from typing import List
import bisect
def longest_increasing_subsequence_binary_search(nums: List[int]) -> int:
"""
Find length of longest increasing subsequence using binary search O(n log n).
Time Complexity: O(n log n)
Space Complexity: O(n)
Maintain array 'tails' where tails[i] = smallest tail of all LIS of length i+1
For each num:
- Find position in tails using binary search
- If position = len(tails), extend the longest subsequence
- Otherwise, replace the value at that position (better tail found)
"""
if not nums:
return 0
tails = []
for num in nums:
pos = bisect.bisect_left(tails, num)
if pos == len(tails):
tails.append(num)
else:
tails[pos] = num
return len(tails)
if __name__ == "__main__":
print(longest_increasing_subsequence_binary_search([10, 9, 2, 5, 3, 7, 101, 18])) # 4
print(longest_increasing_subsequence_binary_search([0, 1, 0, 4, 4, 4, 3, 2, 1])) # 2
print(longest_increasing_subsequence_binary_search([3, 1, 4, 1, 5, 9, 2, 6])) # 4
✓ Simple

A third approach demonstrating an alternative technique for solving this problem. This implementation optimizes either time or space complexity compared to the previous approaches.

⏱ Time O(n) Optimized complexity 💾 Space O(1) Efficient space usage
function approach3():
// Implementation approach goes here
longest_increasing_subsequence_space_optimized.py
"""
Solution for Longest Increasing Subsequence
"""
def solve():
"""Implementation for approach 3 of Longest Increasing Subsequence"""
pass
if __name__ == "__main__":
print("Solution ready")