3113. Max Boundary Subarrays
Find the Number of Subarrays Where Boundary Elements Are Maximum
At first glance, this problem looks quite scary. AC rate is only ~.
However, if we look closer, it's incredibly easy to capture core logic and AC instantly.
I say, this nagging long title is just a bluff 👻
Boundary Elements Must Be the Maximum
The core property of all desired subarrays we need to find.
From here, we immediately lock down a vital observation when traversing nums:
When traversing to :
Any that satisfies where
can't form a valid subarray , where , that meets required criteria.
Why? All because nums[j]$.
as left boundary fails to be the maximum of this subarray.
Any that satisfies with
can be forever eliminated upon traversing to .
Continue From Above
Once we cancel out all where ,
remaining elements is either equal to , or greater.
Our logic simplifies into two scenarios:
I. There is no equal to remaining,
when acts as right boundary, there is only one subarray satisfying requirement:
yep, itself as a single-element subarray.
II. There are existing elements ,
which means we simply increment by 1.
Incremented represents total number of valid left boundaries
that can pair with the right boundary .
In Short
Both scenarios include the case of forming a valid subarray by itself.
However, scenario II also captures when prior identical elements pair up as left boundary.
Monotonicity Again
As of now, you've probably realized that this problem is all about monotonicity.
We implement aforementioned strategy via a strictly decreasing stack.
When traversing to , as long as the stack isn't empty,
and top element satisfies , we pop stack.
After popping all smaller elements,
we might find that stack top has an element exactly equal to .
If so, just do increment: .
Otherwise, we push into the stack with .
Valid left boundaries that right boundary can pair: the count attached to stack top's element.
An essential implementation detail: the count is tied to its respective element itself.
When popping, is also popped away.
All we have to do now is push along with its count into the stack,
and accumulate its count into our final answer subarrays_count.
- C++
- Python
#include <stack>
#include <vector>
using namespace std;
long long count_subarrays(vector<int>& nums) { // LeetCode Q.3113.
stack<pair<int, int>> stack; // Format: {num, count}.
long long subarraysCount = 0;
for (const auto& num : nums) {
while (!stack.empty() && stack.top().first < num) stack.pop();
if (!stack.empty() && stack.top().first == num)
stack.top().second++;
else
stack.push({num, 1});
subarraysCount += stack.top().second;
}
return subarraysCount;
}
def count_subarrays(nums: list[int]) -> int: # LeetCode Q.3113.
stack: list[tuple[int, int]] = [] # Format: (num, count).
subarrays_count = 0
for num in nums:
while stack and stack[-1][0] < num:
stack.pop(-1)
count = 1 # Base case: current num only.
if stack and stack[-1][0] == num:
count += stack.pop(-1)[1]
subarrays_count += count
stack.append((num, count))
return subarrays_count
Both time and space complexities align with typical monotonic stack problems: clean .
Once we see through the traversal elimination mechanism, this problem is an easy AC~~
Follow-up Problems
What are the lower and upper bounds for our final answer subarrays_count?