Longest Increasing Subsequence

Algorithms

The Longest Increasing Subsequence (LIS) problem finds the length of the longest subsequence of a given sequence such that all elements of the subsequence are sorted in increasing order.

Problem Statement

Given an array of integers, find the length of the longest subsequence where elements are in strictly increasing order.

Dynamic Programming Solution

We can solve this using dynamic programming with time complexity, or optimize it to using binary search.

Implementation

import bisect

def lis_dp(arr):
    """Dynamic Programming approach with O(n^2) complexity."""
    n = len(arr)
    
    # Initialize dp array where dp[i] stores the length of LIS ending at index i
    dp = [1] * n
    
    # Compute the LIS for each element in arr
    for i in range(1, n):
        for j in range(i):
            if arr[i] > arr[j]:
                dp[i] = max(dp[i], dp[j] + 1)
    
    # The length of the longest increasing subsequence is the maximum value in dp
    return max(dp)

def lis_optimized(arr):
    """Optimized approach with O(n log n) complexity using binary search."""
    n = len(arr)
    
    # Initialize an empty list to keep track of the smallest possible tail
    lis_tails = []
    
    for num in arr:
        # Find the position where 'num' can replace the current element
        pos = bisect.bisect_left(lis_tails, num)
        
        # If 'num' is larger than any element in lis_tails, it extends the LIS
        if pos == len(lis_tails):
            lis_tails.append(num)
        else:
            lis_tails[pos] = num
    
    # The length of lis_tails is the length of the longest increasing subsequence
    return len(lis_tails)

# Example usage:
arr = [10, 22, 9, 33, 21, 50, 41, 60, 80]

# Calculate LIS using Dynamic Programming approach
lis_length_dp = lis_dp(arr)
print("LIS length using DP approach: {}".format(lis_length_dp))  # Output: 6

# Calculate LIS using Optimized approach
lis_length_optimized = lis_optimized(arr)
print("LIS length using Optimized approach: {}".format(lis_length_optimized))  # Output: 6