You are given an integer array nums
and an integer k
.
Find the longest subsequence of nums
that meets the following requirements:
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
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force method for finding the longest increasing sequence involves exploring every possible subsequence. We systematically generate each subsequence, check if it's increasing, and keep track of the longest one we find. This guarantees we find the true answer, but takes a long time.
Here's how the algorithm would work step-by-step:
def longest_increasing_subsequence_brute_force(sequence):
longest_subsequence_length = 0
for starting_index in range(len(sequence)):
# Consider each element as the start of a potential subsequence.
current_subsequence = [sequence[starting_index]]
current_length = 1
longest_subsequence_length = max(longest_subsequence_length, current_length)
longest_subsequence_length = find_longest_from(
sequence, starting_index, current_subsequence, longest_subsequence_length
)
return longest_subsequence_length
def find_longest_from(sequence, current_index, current_subsequence, longest_subsequence_length):
for next_index in range(current_index + 1, len(sequence)):
# Look for numbers greater than the last number in the current subsequence.
if sequence[next_index] > current_subsequence[-1]:
current_subsequence.append(sequence[next_index])
current_length = len(current_subsequence)
longest_subsequence_length = max(longest_subsequence_length, current_length)
# Recursively find the longest subsequence starting from the next index.
longest_subsequence_length = find_longest_from(
sequence, next_index, current_subsequence, longest_subsequence_length
)
current_subsequence.pop()
#Backtrack to explore other possibilities.
return longest_subsequence_length
The best way to find the longest increasing subsequence, when there's a maximum difference allowed between numbers, is to keep track of the end numbers of all possible increasing sequences we've seen so far. We maintain only the shortest possible sequence for each ending number to optimize for later extensions.
Here's how the algorithm would work step-by-step:
def longest_increasing_subsequence_ii(numbers, max_difference):
tails = {}
for number in numbers:
# Find the longest sequence 'number' can extend.
longest_length = 0
best_tail_value = None
for tail_value, length in tails.items():
if number > tail_value and number - tail_value <= max_difference:
if length > longest_length:
longest_length = length
best_tail_value = tail_value
new_length = longest_length + 1
# If 'number' can extend a sequence.
if best_tail_value is not None:
# Extend the shortest sequence ending with a smaller number
tails[number] = new_length
# Otherwise, 'number' starts a new sequence
else:
tails[number] = 1
# Optimization: Remove longer sequences ending with the same number.
keys_to_remove = []
for tail_value, length in tails.items():
if tail_value > number and length <= new_length:
keys_to_remove.append(tail_value)
for key in keys_to_remove:
del tails[key]
# The result is the length of the longest subsequence.
if not tails:
return 0
return max(tails.values())
Case | How to Handle |
---|---|
Empty input array | Return 0 as the length of the longest increasing subsequence in an empty array is 0. |
Input array with a single element | Return 1 as the longest increasing subsequence contains just that single element. |
Input array with all identical elements | Return 1 because no two elements can be strictly increasing. |
Input array is already sorted in strictly increasing order | The longest increasing subsequence is the array itself, so return the array's length. |
Input array is sorted in strictly decreasing order | The longest increasing subsequence is of length 1, as any single element forms such a sequence; return 1. |
Input array contains negative numbers, zeros and positive numbers | The algorithm should handle this correctly, as long as it compares elements correctly using the < operator. |
Large input array with integer overflow when calculating lengths of subsequences | Ensure that the length of subsequences is stored in a data type that can hold sufficiently large values (e.g., long). |
Large input array that results in exceeding time limit if the algorithm is inefficient | Optimize the algorithm, possibly using binary search or segment tree to achieve O(n log n) time complexity. |