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:
The brute force way to find the longest increasing sequence is to look at every possible sequence you can make from the given numbers. We will check each of these sequences to see if it's increasing, and then remember the longest one we found that actually is.
Here's how the algorithm would work step-by-step:
def find_longest_increasing_subsequence_brute_force(numbers):
longest_subsequence_length = 0
# Iterate through all possible subsequences
for i in range(1 << len(numbers)):
subsequence = []
for j in range(len(numbers)):
# Check if the j-th bit is set in i
if (i >> j) & 1:
subsequence.append(numbers[j])
# Check if subsequence is increasing
is_increasing = True
if len(subsequence) > 1:
for k in range(1, len(subsequence)):
#Ensure each element is greater than the previous
if subsequence[k] <= subsequence[k - 1]:
is_increasing = False
break
if is_increasing:
#Update longest subsequence length found so far
longest_subsequence_length = max(longest_subsequence_length, len(subsequence))
return longest_subsequence_length
The trick is to efficiently keep track of the smallest possible ending number for an increasing sequence of a given length. As we go through the numbers, we update our knowledge of these smallest ending numbers, always aiming to improve the sequences we've seen so far.
Here's how the algorithm would work step-by-step:
def longest_increasing_subsequence(numbers):
smallest_ending_numbers = []
for current_number in numbers:
# Find the smallest ending that current number can extend.
left = 0
right = len(smallest_ending_numbers) - 1
index_to_update = -1
while left <= right:
middle = (left + right) // 2
if smallest_ending_numbers[middle] < current_number:
index_to_update = middle
left = middle + 1
else:
right = middle - 1
# If extends the longest sequence, add to smallest_ending_numbers.
if index_to_update == len(smallest_ending_numbers) - 1:
smallest_ending_numbers.append(current_number)
else:
# If current number improves existing sequence, replace ending.
if index_to_update + 1 < len(smallest_ending_numbers) and current_number < smallest_ending_numbers[index_to_update + 1]:
smallest_ending_numbers[index_to_update + 1] = current_number
# The length of smallest_ending_numbers is the result.
return len(smallest_ending_numbers)
Case | How to Handle |
---|---|
Null or empty input array | Return 0 as the length of the longest increasing subsequence for a null or empty array is 0. |
Array with a single element | Return 1 as a single element array has a longest increasing subsequence of length 1. |
Array with all elements identical | Return 1 since the subsequence can only contain a single element when all elements are the same. |
Array sorted in strictly decreasing order | Return 1, as each element by itself constitutes an increasing subsequence of length 1. |
Array already sorted in strictly increasing order | Return the length of the array as the entire array is the longest increasing subsequence. |
Array contains negative numbers | The algorithm should handle negative numbers correctly as the comparison is based on numerical order, which applies to negative numbers as well. |
Array with a large number of elements to test for performance. | Ensure the algorithm chosen has an optimal time complexity (O(n log n) using patience sorting with binary search) to handle large inputs efficiently, rather than a naive O(n^2) dynamic programming approach. |
Integer overflow if calculating lengths for extremely large arrays. | While the problem only asks for the length, not the subsequence itself, be mindful of potential integer overflows if dealing with extremely long arrays and consider using a larger data type like long if necessary for intermediate calculations. |