The Longest Increasing Subsequence (LIS) problem refers to finding the length of the longest subsequence in an array or sequence such that all elements of the subsequence are sorted in increasing order.
The traditional approach for solving this problem involves using recursion and exploring all possible subsequences in the input array. However, this approach is inefficient since it leads to an exponential runtime complexity.
Dynamic programming is a better approach for solving the LIS problem. The idea behind dynamic programming is to avoid redundant and repeated calculations by storing results of subproblems in a table and using them to solve larger problems.
Here’s how we can use dynamic programming to solve the LIS problem:
1. Define the problem scope: The problem is to find the length of the longest increasing subsequence in the array.
2. Define the state: The state in this problem can be defined as the length of the longest increasing subsequence from index 0 to i in the input array.
3. Define the base case: The base case is when i=0, which means the length of the LIS is 1 since there’s only one element in the subsequence.
4. Define the recurrence relation: The recurrence relation is the formula for calculating the length of the LIS at any index i in the input array. We can calculate the LIS value for given index, by looping over all previous indexes j<i, and checking if the jth value is less than the ith value. If it is less, add 1 to the LIS value for the jth index, and compare it with the LIS value for the ith index. If it’s greater than the current LIS value, update the LIS value for the ith index.
5. Calculate the final result: The final result is the maximum value in the LIS table.
Here’s a sample implementation of the dynamic programming solution for the LIS problem in Java:
public int lengthOfLIS(int[] nums) {
int[] lis = new int[nums.length];
lis[0] = 1;
int maxLength = 1;
for (int i = 1; i < nums.length; i++) {
int maxVal = 0;
for (int j = 0; j < i; j++) {
if (nums[j] < nums[i]) {
maxVal = Math.max(maxVal, lis[j]);
}
}
lis[i] = maxVal + 1;
maxLength = Math.max(maxLength, lis[i]);
}
return maxLength;
}
In this implementation, we define an array lis where lis[i] represents the length of the LIS ending at index i in the input array. We initialize lis[0] to 1 since the base case is when i = 0.
We then loop over the input array, and for each index i, we loop over all previous indexes j<i and check if nums[j] < nums[i]. If this condition is true, we calculate the maximum value in the LIS table for jth index and add 1 to it (to include the current element).
We then update the LIS value in the lis[i] position, and if this value is greater than the current maxLength, we update maxLength with this value.
Finally, we return the maxLength as the result of our LIS calculation.
The runtime complexity of the dynamic programming solution for the LIS problem is O(n2) since we need to loop over all previous indexes for each index in the input array. However, this is much more efficient than the exponential time complexity of the recursive approach. There is also a more advanced O(nlogn) solution to the LIS problem that uses binary search, but this is beyond the scope of this answer.