<p>You are given an array of <strong>positive</strong> integers <code>nums</code>.</p>

<p>Return the number of <span data-keyword="subarray-nonempty">subarrays</span> of <code>nums</code>, where the <strong>first</strong> and the <strong>last</strong> elements of the subarray are <em>equal</em> to the <strong>largest</strong> element in the subarray.</p>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>

<div class="example-block">
<p><strong>Input:</strong> <span class="example-io">nums = [1,4,3,3,2]</span></p>

<p><strong>Output:</strong> <span class="example-io">6</span></p>

<p><strong>Explanation:</strong></p>

<p>There are 6 subarrays which have the first and the last elements equal to the largest element of the subarray:</p>

<ul>
	<li>subarray <code>[<strong><u>1</u></strong>,4,3,3,2]</code>, with its largest element 1. The first element is 1 and the last element is also 1.</li>
	<li>subarray <code>[1,<u><strong>4</strong></u>,3,3,2]</code>, with its largest element 4. The first element is 4 and the last element is also 4.</li>
	<li>subarray <code>[1,4,<u><strong>3</strong></u>,3,2]</code>, with its largest element 3. The first element is 3 and the last element is also 3.</li>
	<li>subarray <code>[1,4,3,<u><strong>3</strong></u>,2]</code>, with its largest element 3. The first element is 3 and the last element is also 3.</li>
	<li>subarray <code>[1,4,3,3,<u><strong>2</strong></u>]</code>, with its largest element 2. The first element is 2 and the last element is also 2.</li>
	<li>subarray <code>[1,4,<u><strong>3,3</strong></u>,2]</code>, with its largest element 3. The first element is 3 and the last element is also 3.</li>
</ul>

<p>Hence, we return 6.</p>
</div>

<p><strong class="example">Example 2:</strong></p>

<div class="example-block">
<p><strong>Input:</strong> <span class="example-io">nums = [3,3,3]</span></p>

<p><strong>Output:</strong> <span class="example-io">6</span></p>

<p><strong>Explanation:</strong></p>

<p>There are 6 subarrays which have the first and the last elements equal to the largest element of the subarray:</p>

<ul>
	<li>subarray <code>[<u><strong>3</strong></u>,3,3]</code>, with its largest element 3. The first element is 3 and the last element is also 3.</li>
	<li>subarray <code>[3,<strong><u>3</u></strong>,3]</code>, with its largest element 3. The first element is 3 and the last element is also 3.</li>
	<li>subarray <code>[3,3,<u><strong>3</strong></u>]</code>, with its largest element 3. The first element is 3 and the last element is also 3.</li>
	<li>subarray <code>[<strong><u>3,3</u></strong>,3]</code>, with its largest element 3. The first element is 3 and the last element is also 3.</li>
	<li>subarray <code>[3,<u><strong>3,3</strong></u>]</code>, with its largest element 3. The first element is 3 and the last element is also 3.</li>
	<li>subarray <code>[<u><strong>3,3,3</strong></u>]</code>, with its largest element 3. The first element is 3 and the last element is also 3.</li>
</ul>

<p>Hence, we return 6.</p>
</div>

<p><strong class="example">Example 3:</strong></p>

<div class="example-block">
<p><strong>Input:</strong> <span class="example-io">nums = [1]</span></p>

<p><strong>Output:</strong> <span class="example-io">1</span></p>

<p><strong>Explanation:</strong></p>

<p>There is a single subarray of <code>nums</code> which is <code>[<strong><u>1</u></strong>]</code>, with its largest element 1. The first element is 1 and the last element is also 1.</p>

<p>Hence, we return 1.</p>
</div>

<p>&nbsp;</p>
<p><strong>Constraints:</strong></p>

<ul>
	<li><code>1 &lt;= nums.length &lt;= 10<sup>5</sup></code></li>
	<li><code>1 &lt;= nums[i] &lt;= 10<sup>9</sup></code></li>
</ul>

class Solution:
    def numberOfSubarrays(self, nums: List[int]) -> int:
        # Find each num's "latest left side" bigger num. Iteration goes in reverse.
        latest_greater_indices = [-1] * len(nums)
        stack = [(-1, nums[-1])]  # Decreasing monotonic stack: (idx, num).

        for current_idx in range(len(nums) - 2, -1, -1):
            if stack:
                future_idx, future_num = stack.pop(-1)
                while future_num < nums[current_idx]:  # Latest found.
                    latest_greater_indices[future_idx] = current_idx
                    if not stack:
                        break
                    future_idx, future_num = stack.pop(-1)

                if future_num >= nums[current_idx]:  # Back to stack.
                    stack.append((future_idx, future_num))

            stack.append((current_idx, nums[current_idx]))

        indices_table = dict()  # Track each num's occurred indices.
        for idx, num in enumerate(nums):
            if num not in indices_table.keys():
                indices_table.update({num: []})
            indices_table[num].append(idx)

        total_subarrays = 0
        for idx, num in enumerate(nums):
            # From start_idx to idx, find how many times num occurs.
            # This counts all valid subarrays ending at idx.

            start_idx = 0  # No last greater.
            if latest_greater_indices[idx] != -1:  # Latest greater exists.
                start_idx += latest_greater_indices[idx] + 1
            
            insertion_idx_1 = self._binary_search(start_idx, indices_table[num])
            insertion_idx_2 = self._binary_search(idx, indices_table[num])
            total_subarrays += insertion_idx_2 - insertion_idx_1 + 1

        return total_subarrays

    @staticmethod
    def _binary_search(index: int, sorted_indices: list[int] | tuple[int]):
        if not sorted_indices:
            return 0

        back_idx, front_idx = 0, len(sorted_indices) - 1
        while back_idx <= front_idx:
            mid_idx = (back_idx + front_idx) // 2
            if sorted_indices[mid_idx] < index:
                back_idx = mid_idx + 1
                continue
            front_idx = mid_idx - 1

        return back_idx  # Number of indices < target idx, implying insertion idx.

1467