Longest Increasing Subsequence in Python

The Longest Increasing Subsequence (LIS) problem asks us to find the length of the longest subsequence in an array where elements are in strictly increasing order. For example, in the array [10,9,2,5,3,7,101,18], the LIS is [2,3,7,101] with length 4.

Algorithm Overview

We'll use a binary search approach with O(n log n) time complexity ?

  • Create a tails array to store the smallest tail element for each possible LIS length
  • For each number, use binary search to find its correct position
  • Update the tails array and track the maximum size

Step-by-Step Algorithm

  • tails := an array of length equal to input array, initialized with zeros
  • size := 0 (tracks current LIS length)
  • For each element x in the input array:
    • Use binary search to find the position where x should be placed
    • Update tails[position] = x
    • Update size if we found a longer subsequence
  • Return the final size

Implementation

class Solution:
    def lengthOfLIS(self, nums):
        if not nums:
            return 0
        
        tails = [0] * len(nums)
        size = 0
        
        for x in nums:
            # Binary search for the correct position
            i, j = 0, size
            while i != j:
                mid = i + (j - i) // 2
                if tails[mid] < x:
                    i = mid + 1
                else:
                    j = mid
            
            # Place x at position i
            tails[i] = x
            size = max(i + 1, size)
        
        return size

# Test the solution
solution = Solution()
nums = [10, 9, 2, 5, 3, 7, 101, 18]
result = solution.lengthOfLIS(nums)
print(f"Input: {nums}")
print(f"Length of LIS: {result}")
Input: [10, 9, 2, 5, 3, 7, 101, 18]
Length of LIS: 4

How It Works

The tails array maintains the smallest ending element for each possible LIS length. For our example ?

# Let's trace through the algorithm step by step
def lengthOfLIS_with_trace(nums):
    tails = [0] * len(nums)
    size = 0
    
    print(f"Processing array: {nums}")
    
    for idx, x in enumerate(nums):
        i, j = 0, size
        while i != j:
            mid = i + (j - i) // 2
            if tails[mid] < x:
                i = mid + 1
            else:
                j = mid
        
        tails[i] = x
        size = max(i + 1, size)
        print(f"Step {idx + 1}: x={x}, position={i}, tails={tails[:size]}, size={size}")
    
    return size

# Trace the example
nums = [10, 9, 2, 5, 3, 7, 101, 18]
result = lengthOfLIS_with_trace(nums)
print(f"\nFinal LIS length: {result}")
Processing array: [10, 9, 2, 5, 3, 7, 101, 18]
Step 1: x=10, position=0, tails=[10], size=1
Step 2: x=9, position=0, tails=[9], size=1
Step 3: x=2, position=0, tails=[2], size=1
Step 4: x=5, position=1, tails=[2, 5], size=2
Step 5: x=3, position=1, tails=[2, 3], size=2
Step 6: x=7, position=2, tails=[2, 3, 7], size=3
Step 7: x=101, position=3, tails=[2, 3, 7, 101], size=4
Step 8: x=18, position=3, tails=[2, 3, 7, 18], size=4

Final LIS length: 4

Alternative: Dynamic Programming Approach

For comparison, here's the simpler O(n²) dynamic programming solution ?

def lengthOfLIS_dp(nums):
    if not nums:
        return 0
    
    dp = [1] * len(nums)  # dp[i] = length of LIS ending at index i
    
    for i in range(1, len(nums)):
        for j in range(i):
            if nums[j] < nums[i]:
                dp[i] = max(dp[i], dp[j] + 1)
    
    return max(dp)

# Test both approaches
nums = [10, 9, 2, 5, 3, 7, 101, 18]
print(f"Binary Search approach: {Solution().lengthOfLIS(nums)}")
print(f"DP approach: {lengthOfLIS_dp(nums)}")
Binary Search approach: 4
DP approach: 4

Comparison

Approach Time Complexity Space Complexity Best For
Binary Search O(n log n) O(n) Large datasets
Dynamic Programming O(n²) O(n) Small datasets, easier to understand

Conclusion

The binary search approach efficiently finds the LIS length in O(n log n) time by maintaining a tails array of smallest ending elements. For large datasets, this approach significantly outperforms the O(n²) dynamic programming solution while using the same space complexity.

Updated on: 2026-03-25T08:03:01+05:30

3K+ Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements