Given an integer array nums
, return the length of the longest strictly increasing subsequence.
Example 1:
Input: nums = [10,9,2,5,3,7,101,18] Output: 4 Explanation: The longest increasing subsequence is [2,3,7,101], therefore the length is 4.
Example 2:
Input: nums = [0,1,0,3,2,3] Output: 4
Example 3:
Input: nums = [7,7,7,7,7,7,7] Output: 1
Constraints:
1 <= nums.length <= 2500
-104 <= nums[i] <= 104
Follow up: Can you come up with an algorithm that runs in O(n log(n))
time complexity?
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:
Imagine you're searching for the longest chain of numbers in a given list, where each number in the chain must be bigger than the one before it. A brute force approach involves checking every single possible chain you could make from the numbers in the list. It's like trying out every path to see which one is the longest climb.
Here's how the algorithm would work step-by-step:
def longest_increasing_subsequence_brute_force(numbers):
max_length = 0
for start_index in range(len(numbers)):
current_length = 0
current_sequence = []
# Start a sequence with the current number
current_sequence.append(numbers[start_index])
current_length = 1
for next_index in range(start_index + 1, len(numbers)):
# Extend sequence only if it increases
if numbers[next_index] > current_sequence[-1]:
current_sequence.append(numbers[next_index])
current_length += 1
# Keep track of the longest one
if current_length > max_length:
max_length = current_length
return max_length
The goal is to find the longest possible ordered chain within a sequence. The key is to build the best possible chain as we go, replacing elements if a better option appears for a chain of a given length.
Here's how the algorithm would work step-by-step:
def find_longest_increasing_subsequence(sequence):
tails = []
for number in sequence:
if not tails or number > tails[-1]:
tails.append(number)
else:
# Find the smallest tail that is >= number.
left, right = 0, len(tails) - 1
while left <= right:
middle = (left + right) // 2
if tails[middle] < number:
left = middle + 1
else:
right = middle - 1
# Replace that found tail.
tails[left] = number
# Length of tails is our LIS length.
return len(tails)
Case | How to Handle |
---|---|
Empty input array | Return 0 as the length of the longest increasing subsequence is 0 when the input is empty. |
Input array with a single element | Return 1, as a single element is a subsequence of length 1. |
Input array with all elements in descending order | The longest increasing subsequence will be of length 1 for each element. |
Input array with all elements being identical | The longest increasing subsequence will be of length 1. |
Input array containing duplicate elements | The algorithm should correctly skip duplicate elements when building the increasing subsequence. |
Input array containing negative numbers and/or zeros | The algorithm should correctly handle negative numbers and zeros as they can be part of an increasing subsequence. |
Input array with extremely large numbers (close to integer limits) | Ensure that the algorithm does not cause integer overflow when comparing elements. |
Large input array, nearing memory limits | A solution with O(n log n) time complexity and O(n) space complexity is preferable to avoid exceeding time or memory limits. |