674. Longest Continuous Increasing Subsequence
Problem Description
You are given an unsorted array of integers nums
. Your task is to find the length of the longest continuous increasing subsequence (subarray) in the array. The subsequence must be strictly increasing.
A continuous increasing subsequence is a subarray defined by two indices l
and r
(where l < r
) such that the subarray is [nums[l], nums[l + 1], ..., nums[r - 1], nums[r]]
, and for each position i
where l <= i < r
, we have nums[i] < nums[i + 1]
.
In other words, you need to find the maximum length of a subarray where each element is strictly greater than the previous element. The elements must be consecutive in the original array (not just any subsequence, but a contiguous subarray).
For example:
- If
nums = [1, 3, 5, 4, 7]
, the longest continuous increasing subsequence is[1, 3, 5]
with length 3 - If
nums = [2, 2, 2, 2, 2]
, since no element is strictly greater than the previous, the answer would be 1 (any single element forms a valid subsequence)
The solution uses a single pass through the array, maintaining a counter cnt
for the current increasing sequence length. Whenever we find an element greater than the previous one, we increment the counter and update the maximum length seen so far. When we encounter an element that's not greater than the previous one, we reset the counter to 1 and start counting a new sequence.
Intuition
The key insight is that we need to find contiguous subarrays where each element is strictly greater than the previous one. Since we're looking for continuous subsequences, we can solve this problem in a single pass through the array.
Think about how you would manually find the longest increasing subarray: you'd start from the beginning and keep counting consecutive increasing elements. When you hit an element that's not greater than the previous one, you'd note down the length you've found so far and start counting again from that position.
This naturally leads to a greedy approach: maintain a running count of the current increasing sequence. As we traverse the array from left to right:
- If
nums[i] > nums[i-1]
, the current element extends our increasing sequence, so we increment our counter - If
nums[i] <= nums[i-1]
, the increasing sequence is broken, so we reset our counter to 1 (starting a new sequence with just the current element)
Throughout this process, we keep track of the maximum length we've seen. This works because:
- Every increasing subsequence must start somewhere and end somewhere
- Once a sequence is broken (by a non-increasing element), there's no way to "repair" it - we must start counting a new sequence
- By checking every possible starting point (which happens naturally when we reset the counter), we're guaranteed to find the maximum length
The beauty of this approach is its simplicity - we only need to compare adjacent elements and maintain two variables: the current sequence length cnt
and the maximum length seen so far ans
. This gives us an optimal O(n)
time complexity with O(1)
space.
Solution Approach
We implement a one-pass scan algorithm that traverses the array while maintaining two variables:
cnt
: tracks the length of the current consecutive increasing sequenceans
: stores the maximum length found so far
Implementation Steps:
-
Initialize variables: Set both
ans = 1
andcnt = 1
. This handles the edge case where the array has only one element, and initializes our current sequence counter. -
Traverse the array: Starting from index 1 (or enumerate from
nums[1:]
), we compare each element with its predecessor:for i, x in enumerate(nums[1:]):
Note that when enumerating
nums[1:]
, the indexi
corresponds to the position in the sliced array, sonums[i]
actually refers to the element just beforex
in the original array. -
Check if sequence continues: For each element
x
at positioni+1
in the original array:- If
nums[i] < x
: The current element is greater than the previous one, so the increasing sequence continues- Increment
cnt
by 1:cnt += 1
- Update the maximum length:
ans = max(ans, cnt)
- Increment
- Otherwise (
nums[i] >= x
): The sequence is broken- Reset
cnt = 1
to start counting a new sequence from the current element
- Reset
- If
-
Return the result: After traversing the entire array,
ans
contains the length of the longest continuous increasing subsequence.
Why this works:
- By comparing adjacent elements, we can immediately determine if a sequence continues or breaks
- Resetting
cnt = 1
when the sequence breaks ensures we start counting fresh from that position - Continuously updating
ans
withmax(ans, cnt)
ensures we never lose track of the longest sequence found - The algorithm processes each element exactly once, giving us
O(n)
time complexity withO(1)
extra space
The elegance of this solution lies in its simplicity - we only need to track the current sequence length and update our answer whenever we find a longer sequence.
Ready to land your dream job?
Unlock your dream job with a 3-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the algorithm with nums = [1, 3, 5, 4, 7, 8, 2]
:
Initial State:
ans = 1
(maximum length found)cnt = 1
(current sequence length)
Step 1: Compare nums[0]=1 with nums[1]=3
- Since 1 < 3, the sequence continues
cnt = 2
(increment counter)ans = max(1, 2) = 2
(update maximum)
Step 2: Compare nums[1]=3 with nums[2]=5
- Since 3 < 5, the sequence continues
cnt = 3
(increment counter)ans = max(2, 3) = 3
(update maximum)
Step 3: Compare nums[2]=5 with nums[3]=4
- Since 5 ≥ 4, the sequence breaks
cnt = 1
(reset counter for new sequence starting at 4)ans = 3
(no update needed)
Step 4: Compare nums[3]=4 with nums[4]=7
- Since 4 < 7, the sequence continues
cnt = 2
(increment counter)ans = max(3, 2) = 3
(no change)
Step 5: Compare nums[4]=7 with nums[5]=8
- Since 7 < 8, the sequence continues
cnt = 3
(increment counter)ans = max(3, 3) = 3
(no change)
Step 6: Compare nums[5]=8 with nums[6]=2
- Since 8 ≥ 2, the sequence breaks
cnt = 1
(reset counter for new sequence starting at 2)ans = 3
(no update needed)
Result: The longest continuous increasing subsequence has length 3, which corresponds to either [1, 3, 5]
or [4, 7, 8]
.
Solution Implementation
1class Solution:
2 def findLengthOfLCIS(self, nums: List[int]) -> int:
3 # Handle edge case of empty array
4 if not nums:
5 return 0
6
7 # Initialize variables
8 # max_length: tracks the maximum length of increasing subsequence found
9 # current_length: tracks the length of current increasing subsequence
10 max_length = 1
11 current_length = 1
12
13 # Iterate through the array starting from the second element
14 for i in range(1, len(nums)):
15 # Check if current element is greater than previous element
16 if nums[i - 1] < nums[i]:
17 # Extend the current increasing subsequence
18 current_length += 1
19 # Update maximum length if current sequence is longer
20 max_length = max(max_length, current_length)
21 else:
22 # Reset current length when sequence breaks
23 current_length = 1
24
25 return max_length
26
1class Solution {
2 /**
3 * Finds the length of the longest continuous increasing subsequence (LCIS).
4 * A continuous increasing subsequence is defined as a subarray where each element
5 * is strictly greater than the previous element.
6 *
7 * @param nums the input array of integers
8 * @return the length of the longest continuous increasing subsequence
9 */
10 public int findLengthOfLCIS(int[] nums) {
11 // Initialize the maximum length to 1 (minimum possible length)
12 int maxLength = 1;
13
14 // Current consecutive increasing sequence length
15 int currentLength = 1;
16
17 // Iterate through the array starting from the second element
18 for (int i = 1; i < nums.length; i++) {
19 // Check if current element is greater than the previous element
20 if (nums[i - 1] < nums[i]) {
21 // Extend the current increasing sequence
22 currentLength++;
23 // Update maximum length if current sequence is longer
24 maxLength = Math.max(maxLength, currentLength);
25 } else {
26 // Reset current sequence length when the increasing pattern breaks
27 currentLength = 1;
28 }
29 }
30
31 return maxLength;
32 }
33}
34
1class Solution {
2public:
3 int findLengthOfLCIS(vector<int>& nums) {
4 // Initialize the maximum length to 1 (single element is always increasing)
5 int maxLength = 1;
6
7 // Track the current increasing subsequence length
8 int currentLength = 1;
9
10 // Iterate through the array starting from the second element
11 for (int i = 1; i < nums.size(); ++i) {
12 // Check if current element is greater than previous element
13 if (nums[i - 1] < nums[i]) {
14 // Extend the current increasing subsequence
15 currentLength++;
16 // Update maximum length if current sequence is longer
17 maxLength = max(maxLength, currentLength);
18 } else {
19 // Reset current length when sequence breaks
20 currentLength = 1;
21 }
22 }
23
24 return maxLength;
25 }
26};
27
1/**
2 * Finds the length of the longest continuous increasing subsequence (LCIS)
3 * @param nums - The input array of numbers
4 * @returns The length of the longest continuous increasing subsequence
5 */
6function findLengthOfLCIS(nums: number[]): number {
7 // Initialize the maximum length and current sequence length
8 let maxLength: number = 1;
9 let currentLength: number = 1;
10
11 // Iterate through the array starting from the second element
12 for (let i: number = 1; i < nums.length; i++) {
13 // Check if current element is greater than previous element
14 if (nums[i - 1] < nums[i]) {
15 // Increment current sequence length
16 currentLength++;
17 // Update maximum length if current sequence is longer
18 maxLength = Math.max(maxLength, currentLength);
19 } else {
20 // Reset current sequence length when sequence breaks
21 currentLength = 1;
22 }
23 }
24
25 return maxLength;
26}
27
Time and Space Complexity
The time complexity is O(n)
, where n
is the length of the array nums
. The algorithm iterates through the array exactly once using the enumerate function starting from index 1 (via nums[1:]
), performing constant-time operations (comparison, increment, and max) for each element.
The space complexity is O(1)
. The algorithm only uses a fixed amount of extra space for variables ans
, cnt
, i
, and x
, regardless of the input size. The slicing operation nums[1:]
in the enumerate function doesn't create a new list in this context as enumerate handles it efficiently through iteration.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Off-by-One Error with Index Comparison
A frequent mistake occurs when using enumerate(nums[1:])
and incorrectly referencing array elements:
Incorrect Implementation:
for i, x in enumerate(nums[1:]):
if nums[i+1] < x: # Wrong! i+1 goes out of bounds
cnt += 1
The Problem: When enumerating nums[1:]
, the index i
starts from 0 but refers to positions in the sliced array. To access the previous element in the original array, you should use nums[i]
, not nums[i+1]
.
Correct Approach:
# Option 1: Use enumerate with proper indexing
for i, x in enumerate(nums[1:]):
if nums[i] < x: # nums[i] is the previous element
cnt += 1
# Option 2: Use range-based iteration (clearer)
for i in range(1, len(nums)):
if nums[i-1] < nums[i]:
cnt += 1
2. Forgetting to Update Maximum Before Resetting
Some implementations update the maximum only when the sequence continues, missing the final sequence:
Incorrect Implementation:
for i in range(1, len(nums)):
if nums[i-1] < nums[i]:
current_length += 1
max_length = max(max_length, current_length)
else:
current_length = 1
# Forgot to update max_length here!
The Problem: If the longest sequence ends at the last element, we never update max_length
after the final increment.
Correct Approach:
Either update max_length
in both branches or add a final check after the loop:
# Option 1: Update in both branches
if nums[i-1] < nums[i]:
current_length += 1
else:
max_length = max(max_length, current_length)
current_length = 1
max_length = max(max_length, current_length) # Final check
# Option 2: Always update when incrementing (as shown in original solution)
if nums[i-1] < nums[i]:
current_length += 1
max_length = max(max_length, current_length)
3. Incorrect Handling of Empty or Single-Element Arrays
Failing to handle edge cases properly:
Incorrect Implementation:
def findLengthOfLCIS(self, nums):
max_length = 1
current_length = 1
for i in range(1, len(nums)): # Crashes if nums is empty!
# ...
Correct Approach:
def findLengthOfLCIS(self, nums):
if not nums:
return 0
if len(nums) == 1:
return 1
# ... rest of the logic
4. Using Non-Strict Comparison
Using <=
instead of <
for the increasing condition:
Incorrect:
if nums[i-1] <= nums[i]: # Wrong! Must be strictly increasing current_length += 1
Correct:
if nums[i-1] < nums[i]: # Strictly less than current_length += 1
This mistake would count sequences with equal consecutive elements as increasing, which violates the problem's requirement for strictly increasing subsequences.
Which of these properties could exist for a graph but not a tree?
Recommended Readings
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!