Skip to main content

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 ~34%34\%.

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 nums[j]nums[j]:

Any nums[i]nums[i] that satisfies nums[i]<nums[j]nums[i] < nums[j] where i<ji < j

can't form a valid subarray nums[i:k+1]nums[i: k + 1], where jkj \le k, that meets required criteria.

Why? All because nums[i]<nums[i] < nums[j]$.

nums[i]nums[i] as left boundary fails to be the maximum of this subarray.

Any nums[i]nums[i] that satisfies nums[i]<nums[j]nums[i] < nums[j] with i<ji < j

can be forever eliminated upon traversing to nums[j]nums[j].

Continue From Above

Once we cancel out all nums[i]<nums[j]nums[i] < nums[j] where i<ji < j,

remaining elements is either equal to nums[j]nums[j], or greater.

Our logic simplifies into two scenarios:

I. There is no nums[i]nums[i] equal to nums[j]nums[j] remaining,

when nums[j]nums[j] acts as right boundary, there is only one subarray satisfying requirement:

yep, nums[j]nums[j] itself as a single-element subarray.

II. There are existing elements nums[i]=nums[j]nums[i] = nums[j],

which means we simply increment Countnums[i]Count_{nums[i]} by 1.

Incremented Countnums[i]Count_{nums[i]} represents total number of valid left boundaries

that can pair with the right boundary nums[j]nums[j].

In Short

Both scenarios include the case of nums[j]nums[j] 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 nums[j]nums[j], as long as the stack isn't empty,

and top element satisfies nums[i]<nums[j]nums[i] < nums[j], we pop stack.

After popping all smaller elements,

we might find that stack top has an element exactly equal to nums[j]nums[j].

If so, just do increment: Countnums[i]+=1Count_{nums[i]} += 1.

Otherwise, we push nums[j]nums[j] into the stack with Countnums[j]=1Count_{nums[j]} = 1.

Valid left boundaries that right boundary nums[j]nums[j] 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, Countnums[i]Count_{nums[i]} is also popped away.

All we have to do now is push nums[j]nums[j] along with its count into the stack,

and accumulate its count into our final answer subarrays_count.


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

Stack_Efficiency Both time and space complexities align with typical monotonic stack problems: clean O(n)O(n).

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?