Longest Increasing Subsequence II
// https://leetcode.com/problems/longest-increasing-subsequence-ii/
/*
You are given an integer array nums and an integer k.
Find the longest subsequence of nums that meets the following requirements:
The subsequence is strictly increasing and
The difference between adjacent elements in the subsequence is at most k.
Return the length of the longest subsequence that meets the requirements.
A subsequence is an array that can be derived from another array by deleting some or no elements without changing the order of the remaining elements.
Ex1:
Input: nums = [4,2,1,4,3,4,5,8,15], k = 3
Output: 5
Explanation:
The longest subsequence that meets the requirements is [1,3,4,5,8].
The subsequence has a length of 5, so we return 5.
Note that the subsequence [1,3,4,5,8,15] does not meet the requirements because 15 - 8 = 7 is larger than 3.
Ex2:
Input: nums = [7,4,5,1,8,12,4,7], k = 5
Output: 4
Explanation:
The longest subsequence that meets the requirements is [4,5,8,12].
The subsequence has a length of 4, so we return 4.
Ex3:
Input: nums = [1,5], k = 1
Output: 1
Explanation:
The longest subsequence that meets the requirements is [1].
The subsequence has a length of 1, so we return 1.
*/
#include <vector>
#include <algorithm>
#include <iostream>
#include <cassert>
using namespace std;
int lengthOfLIS(vector<int>& nums, int k) {
if (nums.empty()) {
return 0;
}
int res = 1;
int n = nums.size();
vector<int> dp(n, 1);
for (int i = 1; i < n; i++) {
for (int j = 0; j < i; j++) {
if (nums[i]-nums[j] <= k && nums[j] < nums[i]) {
dp[i] = max(dp[i], 1+dp[j]);
}
}
res = max(res, dp[i]);
}
return res;
}
// Using segmentation tree.
// The idea is to keep track of length of subsequence ending in number i in the segment tree.
// Time: O(nlogm), Space: O(m)
class SegmentTree{
public:
vector<int> segTree;
int n;
SegmentTree(int n_) : n(n_) {
int size = (int)(ceil(log2(n)));
size = (2 * pow(2, size)) - 1;
segTree = vector<int>(size);
}
int max_value() { return segTree[0]; }
void update(int i, int val) {
// For the end range, we should use n-1, instead of the size of entire seg tree!!
update_util(0, 0, n - 1, i, val);
}
// Update the latest longest length for subsequence for ranges.
void update_util(int idx, int start, int end, int pos, int val) {
if (start == end) {
segTree[idx] = max(val, segTree[idx]);
return;
}
int mid = (start + end) / 2;
if (pos <= mid) {
update_util(2 * idx + 1, start, mid, pos, val);
}
else {
update_util(2 * idx + 2, mid + 1, end, pos, val);
}
segTree[idx] = max(segTree[2 * idx + 1], segTree[2 * idx + 2]);
}
int query(int l, int r) { return query_util(0, 0, n - 1, l, r); }
int query_util(int idx, int start, int end, int l, int r) {
if (r < start || end < l) return INT_MIN;
if (l <= start && end <= r) {
return segTree[idx];
}
int mid = (start + end) / 2;
return max(query_util(2 * idx + 1, start, mid, l, r),
query_util(2 * idx + 2, mid + 1, end, l, r));
}
};
int lengthOfLISSeg(vector<int>& nums, int k) {
SegmentTree seg(1e5 + 1);
for (int i : nums) {
int lower = max(0, i - k);
int q = seg.query(lower, i - 1);
int cur = 1 + q;
seg.update(i, cur);
}
return seg.max_value();
}
int main() {
vector<int> nums1{ 4,2,1,4,3,4,5,8,15 };
int k1 = 3;
assert(lengthOfLIS(nums1, k1) == 5);
assert(lengthOfLISSeg(nums1, k1) == 5);
vector<int> nums2 {7,4,5,1,8,12,4,7};
int k2 = 5;
assert(lengthOfLIS(nums2, k2) == 4);
assert(lengthOfLISSeg(nums2, k2) == 4);
vector<int> nums3 {1,5};
int k3 = 1;
assert(lengthOfLIS(nums3, k3) == 1);
assert(lengthOfLISSeg(nums3, k3) == 1);
return 0;
}```
Last updated