2393. Count Strictly Increasing Subarrays đ
Problem Description
You are given an array nums
consisting of positive integers.
Your task is to count the total number of subarrays that are in strictly increasing order.
A subarray is a contiguous part of an array, meaning the elements must be consecutive in the original array. A subarray is strictly increasing if each element is greater than the previous element (for subarrays with more than one element).
For example, if nums = [1, 3, 2, 4]
:
- The strictly increasing subarrays are:
[1]
,[3]
,[2]
,[4]
,[1, 3]
,[2, 4]
- Total count = 6
Note that single elements are considered strictly increasing subarrays by default.
The solution works by tracking how many strictly increasing subarrays end at each position. For each element, if it's greater than the previous element, we can extend all strictly increasing subarrays ending at the previous position by including the current element, plus the subarray containing just the current element itself. The variable cnt
keeps track of how many strictly increasing subarrays end at the current position, and we accumulate these counts to get the final answer.
Intuition
The key insight is to think about how strictly increasing subarrays are formed and how they relate to each other at different positions in the array.
Consider what happens at each position in the array. Every element by itself forms a valid strictly increasing subarray of length 1. But when we look at an element in relation to its previous element, two scenarios emerge:
-
If the current element is greater than the previous element: All the strictly increasing subarrays that ended at the previous position can be extended to include the current element. For instance, if we had 3 strictly increasing subarrays ending at position
i-1
, we can extend all of them to positioni
, giving us 3 extended subarrays plus the single-element subarray at positioni
. -
If the current element is not greater than the previous element: The strictly increasing sequence is broken. We can't extend any previous subarrays, so we start fresh with only the single-element subarray at the current position.
This leads to a counting pattern. If we maintain a counter cnt
that tracks how many strictly increasing subarrays end at the current position:
- When we can extend (current > previous):
cnt
increases by 1 (we add the extended subarrays plus the single element) - When we can't extend:
cnt
resets to 1 (only the single element subarray)
By accumulating these counts as we traverse the array, we get the total number of strictly increasing subarrays. This works because we're essentially counting each valid subarray exactly once - at the position where it ends.
Learn more about Math and Dynamic Programming patterns.
Solution Approach
The implementation follows a linear scan approach with a running counter to track strictly increasing subarrays.
Algorithm Steps:
-
Initialize variables:
ans
to store the total count of strictly increasing subarrays, initialized to 1 (for the first element)cnt
to track the number of strictly increasing subarrays ending at the current position, initialized to 1
-
Traverse the array using consecutive pairs: Using
pairwise(nums)
, we iterate through consecutive elements(x, y)
wherex
is the previous element andy
is the current element. -
Update the counter based on comparison:
- If
x < y
(strictly increasing): incrementcnt
by 1. This means we can extend allcnt
subarrays that ended atx
to includey
, plus the single-element subarray[y]
- Otherwise: reset
cnt
to 1, as we can only have the single-element subarray[y]
ending at this position
- If
-
Accumulate the count: Add
cnt
toans
after each iteration. This adds the count of all strictly increasing subarrays ending at the current position to our total. -
Return the result: After traversing all pairs,
ans
contains the total count of strictly increasing subarrays.
Example walkthrough with nums = [1, 3, 2, 4]
:
- Start:
ans = 1, cnt = 1
(for element 1) - Pair (1, 3):
1 < 3
, socnt = 2
,ans = 1 + 2 = 3
- Pair (3, 2):
3 ⎠2
, socnt = 1
,ans = 3 + 1 = 4
- Pair (2, 4):
2 < 4
, socnt = 2
,ans = 4 + 2 = 6
- Result: 6 strictly increasing subarrays
Time Complexity: O(n)
where n is the length of the array, as we traverse the array once.
Space Complexity: O(1)
as we only use a constant amount of extra space for variables.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the solution with nums = [2, 5, 3, 6, 7]
.
We'll track cnt
(number of strictly increasing subarrays ending at current position) and ans
(total count).
Initial state:
ans = 1
(for the first element [2])cnt = 1
(one subarray ending at position 0)
Step 1: Compare elements (2, 5)
- Since 2 < 5, we can extend the subarray ending at 2
cnt = cnt + 1 = 2
(subarrays ending at 5: [5] and [2,5])ans = ans + cnt = 1 + 2 = 3
- Running subarrays found: [2], [5], [2,5]
Step 2: Compare elements (5, 3)
- Since 5 ⎠3, we cannot extend any subarray
cnt = 1
(only [3] ends at this position)ans = ans + cnt = 3 + 1 = 4
- New subarray found: [3]
Step 3: Compare elements (3, 6)
- Since 3 < 6, we can extend the subarray ending at 3
cnt = cnt + 1 = 2
(subarrays ending at 6: [6] and [3,6])ans = ans + cnt = 4 + 2 = 6
- New subarrays found: [6], [3,6]
Step 4: Compare elements (6, 7)
- Since 6 < 7, we can extend the subarrays ending at 6
cnt = cnt + 1 = 3
(subarrays ending at 7: [7], [6,7], and [3,6,7])ans = ans + cnt = 6 + 3 = 9
- New subarrays found: [7], [6,7], [3,6,7]
Final Result: 9
All strictly increasing subarrays: [2], [5], [2,5], [3], [6], [3,6], [7], [6,7], [3,6,7]
The key insight: when elements are strictly increasing, cnt
grows because we extend all previous subarrays plus add the single element. When the sequence breaks, cnt
resets to 1, starting fresh.
Solution Implementation
1class Solution:
2 def countSubarrays(self, nums: List[int]) -> int:
3 """
4 Count the number of subarrays where elements are in strictly increasing order.
5
6 Args:
7 nums: List of integers
8
9 Returns:
10 Total count of strictly increasing subarrays
11 """
12 # Initialize result and current subarray length
13 total_count = 1 # Every single element counts as a subarray
14 current_length = 1 # Length of current increasing subarray ending at current position
15
16 # Iterate through consecutive pairs of elements
17 for i in range(1, len(nums)):
18 # Check if current element is greater than previous element
19 if nums[i - 1] < nums[i]:
20 # Extend the current increasing subarray
21 current_length += 1
22 else:
23 # Reset to new subarray starting at current element
24 current_length = 1
25
26 # Add count of all subarrays ending at current position
27 # This includes all increasing subarrays of different lengths ending here
28 total_count += current_length
29
30 return total_count
31
1class Solution {
2 public long countSubarrays(int[] nums) {
3 // Total count of valid subarrays
4 long totalCount = 1;
5
6 // Length of current strictly increasing subarray ending at current position
7 long currentLength = 1;
8
9 // Iterate through the array starting from the second element
10 for (int i = 1; i < nums.length; i++) {
11 // Check if current element is greater than previous element
12 if (nums[i - 1] < nums[i]) {
13 // Extend the current strictly increasing subarray
14 currentLength++;
15 } else {
16 // Reset to new subarray starting at current position
17 currentLength = 1;
18 }
19
20 // Add all subarrays ending at current position to total count
21 // currentLength represents the number of valid subarrays ending at index i
22 totalCount += currentLength;
23 }
24
25 return totalCount;
26 }
27}
28
1class Solution {
2public:
3 long long countSubarrays(vector<int>& nums) {
4 // Total count of valid subarrays
5 long long totalCount = 1;
6
7 // Length of current strictly increasing subarray ending at current position
8 long long 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 strictly increasing subarray
15 ++currentLength;
16 } else {
17 // Reset to new subarray starting at current element
18 currentLength = 1;
19 }
20
21 // Add all subarrays ending at current position to total count
22 // currentLength represents the number of valid subarrays ending at index i
23 totalCount += currentLength;
24 }
25
26 return totalCount;
27 }
28};
29
1/**
2 * Counts the total number of subarrays where elements are in strictly increasing order.
3 * @param nums - The input array of numbers
4 * @returns The total count of strictly increasing subarrays
5 */
6function countSubarrays(nums: number[]): number {
7 // Initialize the total count and current subarray length
8 let totalCount: number = 1; // At least one subarray (first element itself)
9 let currentLength: number = 1; // Length of current increasing subarray
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 // Extend the current increasing subarray
16 currentLength++;
17 } else {
18 // Reset the current subarray length as the increasing pattern breaks
19 currentLength = 1;
20 }
21
22 // Add the number of subarrays ending at current position
23 // This equals the length of the current increasing subarray
24 totalCount += currentLength;
25 }
26
27 return totalCount;
28}
29
Time and Space Complexity
The time complexity is O(n)
, where n
is the length of the array nums
. The algorithm uses pairwise(nums)
to iterate through consecutive pairs of elements in the array, which results in n-1
iterations. Each iteration performs constant time operations: comparing two elements (x < y
), updating the counter cnt
, and adding to ans
. Since we perform a constant amount of work for each of the n-1
pairs, the overall time complexity is linear.
The space complexity is O(1)
. The algorithm only uses a fixed amount of extra space regardless of the input size. The variables ans
, cnt
, x
, and y
are the only additional memory used, and their space requirements don't scale with the input size. The pairwise
iterator doesn't create a new data structure but rather generates pairs on-the-fly, maintaining constant space usage.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Misunderstanding what current_length
represents
Pitfall: Many developers mistakenly think current_length
represents just the length of the longest increasing subarray ending at the current position, missing that it actually represents the count of all strictly increasing subarrays ending at that position.
Why this happens: The variable name current_length
can be misleading. When we have an increasing sequence like [1, 3, 5]
, at position 2 (element 5), current_length = 3
doesn't just mean the longest subarray has length 3. It means there are 3 strictly increasing subarrays ending at position 2: [5]
, [3, 5]
, and [1, 3, 5]
.
Solution: Use a more descriptive variable name like subarrays_ending_here
or add clear comments:
def countSubarrays(self, nums: List[int]) -> int:
total_count = 1
# This represents COUNT of strictly increasing subarrays ending at current position
# NOT the length of the longest subarray
subarrays_ending_here = 1
for i in range(1, len(nums)):
if nums[i - 1] < nums[i]:
# We can extend all previous subarrays + add single element subarray
subarrays_ending_here += 1
else:
# Only the single element subarray is valid
subarrays_ending_here = 1
total_count += subarrays_ending_here
return total_count
2. Forgetting to handle single-element subarrays
Pitfall: Implementing logic that only counts subarrays with 2+ elements, forgetting that single elements are valid strictly increasing subarrays by definition.
Incorrect approach:
def countSubarrays(self, nums: List[int]) -> int:
total_count = 0 # Wrong: missing initial single element
current_length = 0 # Wrong: should start at 1
for i in range(1, len(nums)):
if nums[i - 1] < nums[i]:
current_length += 1
total_count += current_length # Misses single-element subarrays
else:
current_length = 0 # Wrong: should be 1
return total_count
Solution: Always initialize counters to 1 to account for single-element subarrays, and reset to 1 (not 0) when the sequence breaks.
3. Off-by-one errors with array boundaries
Pitfall: Starting the loop at index 0 instead of 1, causing index out of bounds when accessing nums[i-1]
.
Incorrect approach:
def countSubarrays(self, nums: List[int]) -> int:
total_count = 0
current_length = 1
for i in range(len(nums)): # Wrong: should start at 1
if nums[i - 1] < nums[i]: # Error when i = 0
current_length += 1
else:
current_length = 1
total_count += current_length
return total_count
Solution: Start the loop at index 1 and initialize total_count
to 1 to account for the first element, or add boundary checks.
Which type of traversal does breadth first search do?
Recommended Readings
Math for Technical Interviews How much math do I need to know for technical interviews The short answer is about high school level math Computer science is often associated with math and some universities even place their computer science department under the math faculty However the reality is that you
What is Dynamic Programming Prerequisite DFS problems dfs_intro Backtracking problems backtracking Memoization problems memoization_intro Pruning problems backtracking_pruning Dynamic programming is an algorithmic optimization technique that breaks down a complicated problem into smaller overlapping sub problems in a recursive manner and uses solutions to the sub problems to construct a solution
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
Want a Structured Path to Master System Design Too? Donât Miss This!