Given an integer array nums
, return the number of longest increasing subsequences.
Notice that the sequence has to be strictly increasing.
Example 1:
Input: nums = [1,3,5,4,7] Output: 2 Explanation: The two longest increasing subsequences are [1, 3, 4, 7] and [1, 3, 5, 7].
Example 2:
Input: nums = [2,2,2,2,2] Output: 5 Explanation: The length of the longest increasing subsequence is 1, and there are 5 increasing subsequences of length 1, so output 5.
Constraints:
1 <= nums.length <= 2000
-106 <= nums[i] <= 106
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:
To find the number of longest increasing sequences, the brute force way involves checking every possible sequence within the given set of numbers. We examine each subsequence to see if it is increasing and then compare its length to the longest one we've seen so far.
Here's how the algorithm would work step-by-step:
def number_of_longest_increasing_subsequence_brute_force(numbers):
longest_increasing_subsequence_length = 0
number_of_longest_increasing_subsequences = 0
def is_increasing(subsequence):
for i in range(1, len(subsequence)):
if subsequence[i] <= subsequence[i - 1]:
return False
return True
def find_all_subsequences(index, current_subsequence):
nonlocal longest_increasing_subsequence_length
nonlocal number_of_longest_increasing_subsequences
if index == len(numbers):
# Base case: We've reached the end of the input array.
if len(current_subsequence) > 0:
if is_increasing(current_subsequence):
current_length = len(current_subsequence)
# Update longest length, reset count if new longest
if current_length > longest_increasing_subsequence_length:
longest_increasing_subsequence_length = current_length
number_of_longest_increasing_subsequences = 1
# Increment count if same as current longest
elif current_length == longest_increasing_subsequence_length:
number_of_longest_increasing_subsequences += 1
return
# Recursive case 1: Exclude the current number.
find_all_subsequences(index + 1, current_subsequence)
# Recursive case 2: Include the current number.
find_all_subsequences(index + 1, current_subsequence + [numbers[index]])
# Initiates the recursive calls to generate all subsequences
find_all_subsequences(0, [])
# The result holds the total count
return number_of_longest_increasing_subsequences
The optimal approach solves this problem by cleverly building increasing sequences one element at a time. We keep track of both the length of the longest increasing sequence ending at each position, and the number of such sequences. This avoids recalculating information and allows us to efficiently determine the final answer.
Here's how the algorithm would work step-by-step:
def find_number_of_lis(nums): array_length = len(nums)
if array_length == 0:
return 0
lengths = [1] * array_length
counts = [1] * array_length
for i in range(array_length):
for j in range(i):
#Extend LIS if current element is greater.
if nums[i] > nums[j]:
if lengths[j] + 1 > lengths[i]:
lengths[i] = lengths[j] + 1
#Reset count for new longest
counts[i] = counts[j]
elif lengths[j] + 1 == lengths[i]:
#Accumulate counts for equal length
counts[i] += counts[j]
longest_sequence_length = max(lengths)
number_of_longest_sequences = 0
#Sum counts of all LIS with max length
for i in range(array_length):
if lengths[i] == longest_sequence_length:
number_of_longest_sequences += counts[i]
return number_of_longest_sequences
Case | How to Handle |
---|---|
Empty input array | Return 0, since there's no increasing subsequence. |
Array with a single element | Return 1, as the single element itself forms an increasing subsequence of length 1, with count 1. |
Array with all identical values | Return 1, as each element is a LIS of length 1, but only one is counted. |
Array in strictly decreasing order | Return the length of the array (n), as each element is a LIS of length 1, and there are n of them. |
Array with maximum integer values | Ensure that integer overflow does not occur when calculating the count of LIS, potentially using larger data types for counts. |
Large input array size | Ensure the solution has acceptable time complexity, such as O(n^2) using dynamic programming. |
Array with duplicate numbers | Dynamic programming approach handles duplicates naturally by considering only increasing subsequences. |
Input array with negative numbers | The dynamic programming approach correctly handles negative numbers without any modification. |