Longest Increasing Subsequence (LIS)
Algorithm Explanation
The Longest Increasing Subsequence (LIS) problem involves finding the longest subsequence of a sequence such that all elements of the subsequence are sorted in increasing order.
Dynamic Programming (O(n2)) Approach
- Initialize a dp[] array of size n where dp[i] represents the length of the LIS ending at index i.
- For each i from 1 to n-1, iterate over all j from 0 to i-1:
If arr[i] > arr[j], update dp[i] = max(dp[i], dp[j] + 1).
- The answer is the maximum value in dp[].
Efficient Binary Search Approach (O(n log n))
- Maintain a tail[] array that stores the smallest possible tail value for all increasing subsequences
with length i+1 in tail[i].
- For each element x in the input, use binary search to find the smallest index in tail where tail[i] >= x,
and replace or append accordingly.
Complexity Analysis
- Time Complexity: O(n log n) using binary search approach
- Space Complexity: O(n) for the tail array
Easy Problems Solvable Using LIS
1. Find Length of LIS
Problem: Given an array, find the length of the LIS.
#include <iostream>
#include <vector>
#include <algorithm>
int lengthOfLIS(std::vector<int>& nums) {
std::vector<int> tail;
for (int num : nums) {
auto it = std::lower_bound(tail.begin(), tail.end(), num);
if (it == tail.end()) tail.push_back(num);
else *it = num;
}
return tail.size();
}
int main() {
std::vector<int> nums = {10, 9, 2, 5, 3, 7, 101, 18};
std::cout << lengthOfLIS(nums);
return 0;
}
2. Check If Subsequence Is Increasing
Problem: Given a sequence, determine if it's an increasing subsequence of another array.
#include <iostream>
#include <vector>
bool isIncreasingSubsequence(const std::vector<int>& arr, const std::vector<int>& seq) {
int i = 0;
for (int num : arr) {
if (i < seq.size() && seq[i] == num) i++;
}
return i == seq.size();
}
int main() {
std::vector<int> arr = {1, 3, 5, 6, 7};
std::vector<int> seq = {1, 5, 7};
std::cout << isIncreasingSubsequence(arr, seq);
return 0;
}
Intermediate Problems Solvable Using LIS
1. Maximum Sum Increasing Subsequence
#include <iostream>
#include <vector>
#include <algorithm>
int maxSumIS(std::vector<int>& arr) {
int n = arr.size();
std::vector<int> dp = arr;
for (int i = 1; i < n; i++) {
for (int j = 0; j < i; j++) {
if (arr[i] > arr[j]) {
dp[i] = std::max(dp[i], dp[j] + arr[i]);
}
}
}
return *std::max_element(dp.begin(), dp.end());
}
int main() {
std::vector<int> arr = {1, 101, 2, 3, 100, 4, 5};
std::cout << maxSumIS(arr);
return 0;
}
2. Number of LIS
Problem: Count how many distinct LIS are there.
#include <iostream>
#include <vector>
#include <algorithm>
int findNumberOfLIS(std::vector<int>& nums) {
int n = nums.size(), maxLen = 0, res = 0;
std::vector<int> len(n, 1), cnt(n, 1);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < i; ++j) {
if (nums[i] > nums[j]) {
if (len[j] + 1 > len[i]) {
len[i] = len[j] + 1;
cnt[i] = cnt[j];
} else if (len[j] + 1 == len[i]) {
cnt[i] += cnt[j];
}
}
}
if (len[i] > maxLen) {
maxLen = len[i];
res = cnt[i];
} else if (len[i] == maxLen) {
res += cnt[i];
}
}
return res;
}
int main() {
std::vector<int> nums = {1, 3, 5, 4, 7};
std::cout << findNumberOfLIS(nums);
return 0;
}
Hard Problem Solvable Using LIS
Russian Doll Envelopes
Problem: Given envelopes with widths and heights, find the max number that can be nested.
#include <iostream>
#include <vector>
#include <algorithm>
int maxEnvelopes(std::vector<std::vector<int>>& envelopes) {
std::sort(envelopes.begin(), envelopes.end(), [](auto& a, auto& b) {
return a[0] == b[0] ? a[1] > b[1] : a[0] < b[0];
});
std::vector<int> dp;
for (auto& env : envelopes) {
auto it = std::lower_bound(dp.begin(), dp.end(), env[1]);
if (it == dp.end()) dp.push_back(env[1]);
else *it = env[1];
}
return dp.size();
}
int main() {
std::vector<std::vector<int>> envelopes = {{5,4}, {6,4}, {6,7}, {2,3}};
std::cout << maxEnvelopes(envelopes);
return 0;
}