Back to all solutions

#2407 - Longest Increasing Subsequence II

Problem 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.

Solution

/**
 * @param {number[]} nums
 * @param {number} k
 * @return {number}
 */
var lengthOfLIS = function(nums, k) {
  const maxValue = Math.max(...nums);
  const tree = new Array(4 * maxValue).fill(0);

  for (const currentNum of nums) {
    const rangeStart = Math.max(1, currentNum - k);
    const rangeEnd = currentNum - 1;

    const bestPreviousLength = rangeEnd >= rangeStart
      ? queryRange(1, 1, maxValue, rangeStart, rangeEnd) : 0;
    updatePosition(1, 1, maxValue, currentNum, bestPreviousLength + 1);
  }

  return queryRange(1, 1, maxValue, 1, maxValue);

  function updatePosition(nodeIndex, treeStart, treeEnd, position, newLength) {
    if (treeStart === treeEnd) {
      tree[nodeIndex] = Math.max(tree[nodeIndex], newLength);
    } else {
      const treeMid = Math.floor((treeStart + treeEnd) / 2);
      if (position <= treeMid) {
        updatePosition(2 * nodeIndex, treeStart, treeMid, position, newLength);
      } else {
        updatePosition(2 * nodeIndex + 1, treeMid + 1, treeEnd, position, newLength);
      }
      tree[nodeIndex] = Math.max(tree[2 * nodeIndex], tree[2 * nodeIndex + 1]);
    }
  }

  function queryRange(nodeIndex, treeStart, treeEnd, queryStart, queryEnd) {
    if (queryEnd < treeStart || treeEnd < queryStart) {
      return 0;
    }
    if (queryStart <= treeStart && treeEnd <= queryEnd) {
      return tree[nodeIndex];
    }
    const mid = Math.floor((treeStart + treeEnd) / 2);
    return Math.max(
      queryRange(2 * nodeIndex, treeStart, mid, queryStart, queryEnd),
      queryRange(2 * nodeIndex + 1, mid + 1, treeEnd, queryStart, queryEnd)
    );
  }
};