The Longest Increasing Subsequence (LIS) problem is the task of finding the length of the longest increasing subsequence of a given sequence of numbers. An increasing subsequence is a sequence of numbers in which each number is greater than the previous number. For example, in the sequence 3, 1, 4, 1, 5, 9, 2, 6, 5, the longest increasing subsequence is 1, 2, 5, 6 with length 4.
There are several algorithmic approaches to solving the LIS problem, including dynamic programming and binary search.
Dynamic programming is a common approach to solving the LIS problem. In this approach, we maintain a table that stores the length of the longest increasing subsequence ending at each element in the sequence. We start by initializing each element in the table to 1, since the longest increasing subsequence that ends at an element with only one number is itself. Then, for each element in the sequence, we compare it to all previous elements to see if it can be included in a longer increasing subsequence. If the element is greater than a previous element, we add 1 to the length of the longest increasing subsequence that ends at that previous element, and compare this length to the length of the longest increasing subsequence that ends at the current element. The length of the longest increasing subsequence that ends at the current element is then stored in the table.
Here is an example implementation of the dynamic programming approach to solving the LIS problem:
def lis(sequence):
n = len(sequence)
table = [1] * n
for i in range(1, n):
for j in range(i):
if sequence[i] > sequence[j]:
table[i] = max(table[i], table[j] + 1)
return max(table)
The time complexity of this approach is O(n2), since we need to compare each element to all previous elements.
Another approach to solving the LIS problem is to use binary search. In this approach, we maintain a list of numbers that represent the smallest possible end element of an increasing subsequence of length i, for i=1,2,3,...,n. We start with an empty list, and for each element in the sequence, we perform a binary search on the list to find the index where the current element can be inserted to maintain the increasing order of the list. We then replace the element at that index with the current element, or append the current element to the list if it is greater than all elements in the list. The length of the list is the length of the longest increasing subsequence.
Here is an example implementation of the binary search approach to solving the LIS problem:
import bisect
def lis(sequence):
n = len(sequence)
ends = []
for i in range(n):
index = bisect.bisect_left(ends, sequence[i])
if index == len(ends):
ends.append(sequence[i])
else:
ends[index] = sequence[i]
return len(ends)
The time complexity of this approach is O(n log n), since we perform a binary search for each element in the sequence.