Skip to content
← All posts

Count Number of Teams: Fix the Middle Element

6 min read
leetcodeproblemmediumarrays

Given an array rating of unique integers where rating[i] is the rating of the i-th soldier, count the number of teams of 3 soldiers (i, j, k) such that i < j < k and either rating[i] < rating[j] < rating[k] (increasing) or rating[i] > rating[j] > rating[k] (decreasing).

This is LeetCode 1395: Count Number of Teams, and it is an excellent problem for learning how to count triplets efficiently by fixing the middle element and combining contributions from both sides.

IncreasingDecreasing2,3,42i=05i=13i=24i=31i=45,3,15,4,1
rating = [2, 5, 3, 4, 1]. Green arcs show increasing triplets (2,3,4). Yellow arcs show decreasing triplets (5,3,1) and (5,4,1). Total valid teams: 3.

Why this problem matters

Brute force would check all O(n^3) triplets, which is too slow. This problem teaches a powerful counting technique: instead of iterating over all possible triplets, you fix one element and figure out how many valid configurations surround it. This "fix one, count the rest" pattern appears in many array counting problems, including problems about subsequences, pairs, and inversions.

Once you internalize the idea of fixing the middle element and multiplying left and right contributions, you will recognize it in problems like 3Sum, Number of Longest Increasing Subsequence, and 132 Pattern.

The key insight

The key insight is to fix the middle element. For each index j, count:

  • left_less: elements before j that are smaller than rating[j]
  • left_greater: elements before j that are larger than rating[j]
  • right_less: elements after j that are smaller than rating[j]
  • right_greater: elements after j that are larger than rating[j]

Increasing triplets through j = left_less * right_greater

Decreasing triplets through j = left_greater * right_less

Why does this work? For an increasing triplet (i, j, k), you need some element before j that is smaller (that is i) and some element after j that is larger (that is k). Each valid i can pair with each valid k independently, so you multiply the counts. The same logic applies in reverse for decreasing triplets.

The solution

def num_teams(rating: list[int]) -> int:
    n = len(rating)
    count = 0

    for j in range(n):
        left_less = 0
        left_greater = 0
        right_less = 0
        right_greater = 0

        for i in range(j):
            if rating[i] < rating[j]:
                left_less += 1
            elif rating[i] > rating[j]:
                left_greater += 1

        for k in range(j + 1, n):
            if rating[k] > rating[j]:
                right_greater += 1
            elif rating[k] < rating[j]:
                right_less += 1

        count += left_less * right_greater
        count += left_greater * right_less

    return count

For each middle index j, we scan everything to the left and count how many values are smaller versus larger than rating[j]. Then we scan everything to the right and do the same. The number of increasing triplets through j is left_less * right_greater, because any of the left_less elements can serve as the first element and any of the right_greater elements can serve as the third. We add left_greater * right_less for the decreasing triplets. Summing over all j gives the total count.

Since all ratings are unique, you never need to worry about the case where rating[i] == rating[j]. The elif branches handle everything cleanly, and you never accidentally double-count or miss a comparison.

Visual walkthrough

Let's trace through rating = [2, 5, 3, 4, 1] step by step. For each middle element j, we count the left and right contributions and compute the number of valid triplets passing through that position.

Step 1: Fix j=1 (rating[1]=5) as the middle element

2i=05i=13i=24i=31i=4
left_less = 1
right_greater = 0
left_greater = 0
right_less = 3
increasing = 1 * 0 = 0
decreasing = 0 * 3 = 0

Left of j=1: [2]. Values less than 5: {2}, so left_less=1. Values greater than 5: none, so left_greater=0. Right of j=1: [3,4,1]. Values greater than 5: none, so right_greater=0. Values less than 5: {3,4,1}, so right_less=3. Increasing: 1*0=0. Decreasing: 0*3=0.

Step 2: Fix j=2 (rating[2]=3) as the middle element

2i=05i=13i=24i=31i=4
left_less = 1
right_greater = 1
left_greater = 1
right_less = 1
increasing = 1 * 1 = 1
decreasing = 1 * 1 = 1

Left of j=2: [2,5]. Less than 3: {2}, left_less=1. Greater than 3: {5}, left_greater=1. Right of j=2: [4,1]. Greater than 3: {4}, right_greater=1. Less than 3: {1}, right_less=1. Increasing: 1*1=1. Decreasing: 1*1=1.

Step 3: Fix j=3 (rating[3]=4) as the middle element

2i=05i=13i=24i=31i=4
left_less = 2
right_greater = 0
left_greater = 1
right_less = 1
increasing = 2 * 0 = 0
decreasing = 1 * 1 = 1

Left of j=3: [2,5,3]. Less than 4: {2,3}, left_less=2. Greater than 4: {5}, left_greater=1. Right of j=3: [1]. Greater than 4: none, right_greater=0. Less than 4: {1}, right_less=1. Increasing: 2*0=0. Decreasing: 1*1=1.

Step 4: Sum all contributions

Total increasing: 0 + 1 + 0 = 1

Total decreasing: 0 + 1 + 1 = 2

Answer: 1 + 2 = 3 teams

Total increasing triplets: 0 + 1 + 0 = 1. Total decreasing triplets: 0 + 1 + 1 = 2. Grand total: 1 + 2 = 3 teams.

Notice that j=0 and j=4 (the first and last elements) can never be the middle element of a triplet, so we only need to consider j=1, 2, 3. Each middle element contributes independently, and the grand total is the sum of all contributions.

Complexity analysis

ApproachTimeSpace
Fix middle elementO(n^2)O(1)

Time is O(n^2). For each of the n positions j, we scan up to n elements to the left and n elements to the right. The total work is proportional to n^2. This is a large improvement over the O(n^3) brute force that checks every triplet directly.

Space is O(1). We only use a handful of integer variables (the four counters and the running total). No additional arrays or data structures are needed.

The building blocks

1. Fix the middle element

The core technique here is choosing one position to "anchor" and counting valid configurations around it. Instead of iterating over all triples (i, j, k), you iterate over j and ask: "how many valid i values exist on the left, and how many valid k values exist on the right?" This reduces a three-variable problem to a one-variable problem with two sub-scans.

for j in range(n):
    left_less = sum(1 for i in range(j) if rating[i] < rating[j])
    right_greater = sum(1 for k in range(j + 1, n) if rating[k] > rating[j])
    count += left_less * right_greater

2. Multiplication principle for independent choices

When two choices are independent (picking i from the left does not constrain which k you pick from the right), the total number of valid combinations is the product of the individual counts. This is the multiplication principle from combinatorics. You will see it in problems like 3Sum (after sorting), counting rectangles, and any problem where you decompose a multi-element selection into independent parts.

3. Symmetric counting for both directions

The same logic that counts increasing triplets also counts decreasing ones. You just swap which counts you multiply: left_greater * right_less instead of left_less * right_greater. Recognizing this symmetry means you only need to write the counting logic once and apply it twice with different variable pairings.

Edge cases

  • All ratings in increasing order (e.g., [1, 2, 3, 4]): every triplet of indices (i, j, k) with i < j < k is valid as an increasing triplet. The count equals C(n, 3) = n*(n-1)*(n-2)/6. No decreasing triplets exist.
  • All ratings in decreasing order (e.g., [4, 3, 2, 1]): symmetric to the above. Every triplet is a valid decreasing triplet. No increasing triplets exist.
  • n = 3: there is exactly one triplet to check. The answer is 0, 1, or 2 depending on whether the three values are increasing, decreasing, or neither.
  • n < 3: impossible to form any team. Return 0. (The constraints guarantee n is at least 1, so handle this as a guard clause.)
  • Two equal ratings: the problem states all ratings are unique, so you do not need to handle ties. Every comparison is strict.

From understanding to recall

You have seen how fixing the middle element turns a triple-nested loop into a double loop with clean counting. The logic is a direct application of the multiplication principle: left choices times right choices. But reproducing it under pressure requires more than understanding.

The details that matter: scanning left for both "less" and "greater" counts, scanning right for both, and multiplying the correct pairs (left_less with right_greater for increasing, left_greater with right_less for decreasing). Mixing up the pairings gives the wrong answer. Forgetting to sum over all j gives a partial answer.

Spaced repetition makes these details automatic. You practice writing the middle-element loop, the four counters, and the two multiplication lines from scratch at increasing intervals. After a few rounds, you do not need to re-derive the pairing logic. You just write it.

Related posts

  • Longest Increasing Subsequence - The classic dynamic programming problem for increasing subsequences, building on the same "compare elements in order" intuition
  • Number of Longest Increasing Subsequence - Extends LIS to count the number of such subsequences, using similar multiplicative counting
  • 132 Pattern - Another triplet-finding problem that rewards fixing one element and reasoning about what appears on either side

CodeBricks breaks Count Number of Teams into its middle-element fixing, left-right scanning, and multiplicative counting building blocks, then drills them independently with spaced repetition. You type each piece from scratch until the pattern is automatic. When a triplet counting problem shows up in your interview, you do not hesitate. You just write it.