Skip to content

2407. Longest Increasing Subsequence II

Description

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.

 

Example 1:

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.

Example 2:

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.

Example 3:

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.

 

Constraints:

  • 1 <= nums.length <= 105
  • 1 <= nums[i], k <= 105

 

Solutions

Solution: Segment Tree

  • Time complexity: O(nlog*Max(nums))
  • Space complexity: O(Max(nums))

 

JavaScript

js
/**
 * @param {number[]} nums
 * @param {number} k
 * @return {number}
 */
const lengthOfLIS = function (nums, k) {
  const maxNum = Math.max(...nums);
  const tree = new SegmentTree(maxNum + 1);
  let result = 0;

  for (const num of nums) {
    const min = Math.max(0, num - k);
    const max = num - 1;
    const longestSubseq = tree.query(min, max) + 1;

    tree.update(num, longestSubseq);
    result = Math.max(longestSubseq, result);
  }

  return result;
};

class SegmentTree {
  constructor(n) {
    this.n = n;
    this.longestSubseq = Array.from({ length: this.n * 4 }, () => 0);
  }

  update(num, len) {
    this.#update(0, 0, this.n - 1, num, len);
  }

  #update(index, low, high, num, len) {
    if (num < low || num > high) return;

    if (low === high) {
      this.longestSubseq[index] = Math.max(len, this.longestSubseq[index]);
      return;
    }

    const mid = Math.floor((low + high) / 2);

    if (num <= mid) {
      this.#update(index * 2 + 1, low, mid, num, len);
    } else {
      this.#update(index * 2 + 2, mid + 1, high, num, len);
    }

    this.longestSubseq[index] = Math.max(this.longestSubseq[index * 2 + 1], this.longestSubseq[index * 2 + 2]);
  }

  query(left, right) {
    return this.#query(0, 0, this.n - 1, left, right);
  }

  #query(index, low, high, left, right) {
    if (left > high || right < low) return 0;

    if (low >= left && high <= right) {
      return this.longestSubseq[index];
    }

    const mid = Math.floor((low + high) / 2);
    const leftQuery = this.#query(index * 2 + 1, low, mid, left, right);
    const rightQuery = this.#query(index * 2 + 2, mid + 1, high, left, right);

    return Math.max(leftQuery, rightQuery);
  }
}

Released under the MIT license