medium Count Number of Teams
Problem Statement
There are n soldiers standing in a line. Each soldier has a unique rating value.
You need to form a team of 3 soldiers under these rules:
- Choose three soldiers with indices
(i, j, k)and ratings(rating[i], rating[j], rating[k]). - A team is valid if:
(rating[i] < rating[j] < rating[k])or(rating[i] > rating[j] > rating[k])- where
(0 <= i < j < k < n).
Return the count of the valid teams that can be formed under these conditions.
Examples
Example 1:
- Input: rating =
[3, 6, 2, 8, 1, 5] - Expected Output:
3 - Justification: The valid teams are:
(3, 2, 1)(3, 6, 8)(6, 2, 1)
Example 2:
- Input: rating =
[1, 5, 3, 2, 6, 4] - Expected Output:
6 - Justification: The valid teams are:
(1, 3, 6)(1, 2, 6)(1, 2, 4)(5, 3, 2)(5, 3, 4)(1, 5, 6)
Example 3:
- Input: rating =
[10, 20, 30, 25, 15] - Expected Output:
3 - Justification: The valid teams are:
(10, 20, 30)(10, 20, 25)(30, 25, 15)
Constraints:
- n == rating.length
- 3 <= n <= 1000
- 1 <= rating[i] <= 105
- All the integers in rating are
unique.
Try it yourself
Try solving this question here:
✅ Solution Count Number of Teams
Problem Statement
There are n soldiers standing in a line. Each soldier has a unique rating value.
You need to form a team of 3 soldiers under these rules:
- Choose three soldiers with indices
(i, j, k)and ratings(rating[i], rating[j], rating[k]). - A team is valid if:
(rating[i] < rating[j] < rating[k])or(rating[i] > rating[j] > rating[k])- where
(0 <= i < j < k < n).
Return the count of the valid teams that can be formed under these conditions.
Examples
Example 1:
- Input: rating =
[3, 6, 2, 8, 1, 5] - Expected Output:
3 - Justification: The valid teams are:
(3, 2, 1)(3, 6, 8)(6, 2, 1)
Example 2:
- Input: rating =
[1, 5, 3, 2, 6, 4] - Expected Output:
6 - Justification: The valid teams are:
(1, 3, 6)(1, 2, 6)(1, 2, 4)(5, 3, 2)(5, 3, 4)(1, 5, 6)
Example 3:
- Input: rating =
[10, 20, 30, 25, 15] - Expected Output:
3 - Justification: The valid teams are:
(10, 20, 30)(10, 20, 25)(30, 25, 15)
Constraints:
- n == rating.length
- 3 <= n <= 1000
- 1 <= rating[i] <= 105
- All the integers in rating are
unique.
Solution
To solve this problem, we use segment trees to efficiently count the number of valid teams. The idea is to use two segment trees: one for keeping track of the number of ratings to the left of the current soldier and another for ratings to the right. This allows us to efficiently query the number of ratings that are either less than or greater than the current rating in constant time.
The segment trees are updated as we iterate through the array. For each soldier, we count the number of valid teams by combining the counts from the left and right segment trees. By maintaining these counts, we can quickly determine the number of valid teams without having to repeatedly iterate over the entire array, making the solution more efficient.
Step-by-Step Algorithm
-
Initialize Variables:
- Step 1.1: Initialize
teamCountto0. This variable will store the total number of valid teams. - Step 1.2: Calculate
maxRatingas the maximum rating in theratingsarray plus1. This helps in sizing the segment trees correctly to handle the range of rating values. - Step 1.3: Initialize
leftSegmentTreeandrightSegmentTreeas integer arrays of size4 * maxRating. These trees will keep track of the counts of ratings to the left and right of the current rating, respectively.
- Step 1.1: Initialize
-
Build Initial Segment Trees:
- Step 2.1: Iterate through the
ratingsarray starting from the second element to the last element. - Step 2.2: For each rating in this iteration, update the
rightSegmentTreeby adding one to the count of the current rating using theupdatemethod. This step initializes the right segment tree with counts of all ratings except the first. This setup allows us to easily keep track of the counts of ratings to the right of the current rating as we iterate through the array.
- Step 2.1: Iterate through the
-
Update Left Segment Tree with First Rating:
- Step 3.1: Update the
leftSegmentTreeby adding one to the count of the first rating using theupdatemethod. This step sets up the left segment tree to start tracking the counts of ratings to the left of the current rating as we iterate through the array.
- Step 3.1: Update the
-
Iterate Through Ratings:
- Step 4.1: Iterate through the
ratingsarray starting from the second element to the last element. For each rating at indexi, perform the following steps:
- Step 4.1: Iterate through the
-
Count Teams with a Lower Rating on the Left and a Higher Rating on the Right:
- Step 5.1: Use the
sumRangemethod to query theleftSegmentTreefor the number of ratings less than the current rating. This count is stored inleftLessCount. - Step 5.2: Use the
sumRangemethod to query therightSegmentTreefor the number of ratings greater than the current rating. This count is stored inrightGreaterCount. - Step 5.3: Multiply
leftLessCountandrightGreaterCountand add the result toteamCount. This step counts the valid teams where the current rating is in the middle, with a lower rating on the left and a higher rating on the right.
- Step 5.1: Use the
-
Count Teams with a Higher Rating on the Left and a Lower Rating on the Right:
- Step 6.1: Use the
sumRangemethod to query theleftSegmentTreefor the number of ratings greater than the current rating. This count is stored inleftGreaterCount. - Step 6.2: Use the
sumRangemethod to query therightSegmentTreefor the number of ratings less than the current rating. This count is stored inrightLessCount. - Step 6.3: Multiply
leftGreaterCountandrightLessCountand add the result toteamCount. This step counts the valid teams where the current rating is in the middle, with a higher rating on the left and a lower rating on the right.
- Step 6.1: Use the
-
Update Segment Trees:
- Step 7.1: Update the
leftSegmentTreeby adding one to the count of the current rating using theupdatemethod. This step updates the left segment tree to include the current rating, as it will be to the left of subsequent ratings. - Step 7.2: Update the
rightSegmentTreeby subtracting one from the count of the current rating using theupdatemethod. This step updates the right segment tree to exclude the current rating, as it has been processed and will no longer be to the right of any subsequent ratings.
- Step 7.1: Update the
-
Return the Total Number of Teams:
- Step 8.1: Return the value of
teamCount, which now contains the total number of valid teams.
- Step 8.1: Return the value of
Explanation of update() Method
- Step 1: If
lowequalshigh, it means we are at a leaf node in the segment tree. In this case, update the value at this node by addingvaluetosegTree[index]. - Step 2: If
lowis not equal tohigh, calculate the middle pointmidas(low + high) / 2. - Step 3: If
positionlies betweenlowandmid, recursively callupdateon the left child (2 * index + 1) with updated parameters. - Step 4: If
positionlies betweenmid + 1andhigh, recursively callupdateon the right child (2 * index + 2) with updated parameters. - Step 5: After updating the appropriate child, update the current node value as the sum of its two children (
segTree[index] = segTree[2 * index + 1] + segTree[2 * index + 2]).
Explanation of sumRange() Method
- Step 1: If
lowtohighis completely within thelefttorightrange, returnsegTree[index]. - Step 2: If there is no overlap between
lowtohighandlefttoright, return0. - Step 3: If there is a partial overlap, calculate the middle point
midas(low + high) / 2. - Step 4: Recursively query the left and right children (
2 * index + 1and2 * index + 2) and sum their results to get the total range sum for the current node's range.
Algorithm Walkthrough
Input: [3, 6, 2, 8, 1, 5]
1. Initialize Variables:
teamCount = 0maxRating = 9(since max rating is 8 + 1)leftSegmentTree = new int[36](4 * maxRating)rightSegmentTree = new int[36](4 * maxRating)
2. Build Initial Right Segment Tree:
-
For rating
6(index 1):- Call
update(0, 1, 0, 8, 6, rightSegmentTree)low = 0,high = 8,mid = 46 > 4, so callupdate(2, 1, 5, 8, 6, rightSegmentTree)low = 5,high = 8,mid = 66 <= 6, so callupdate(5, 1, 5, 6, 6, rightSegmentTree)low = 5,high = 6,mid = 56 > 5, so callupdate(12, 1, 6, 6, 6, rightSegmentTree)low = 6,high = 6(leaf node), updaterightSegmentTree[12] += 1
- Update
rightSegmentTree[5] = rightSegmentTree[11] + rightSegmentTree[12] = 0 + 1 = 1
- Update
rightSegmentTree[2] = rightSegmentTree[5] + rightSegmentTree[6] = 1 + 0 = 1
- Update
rightSegmentTree[0] = rightSegmentTree[1] + rightSegmentTree[2] = 0 + 1 = 1
- Call
-
For rating
2(index 2):- Call
update(0, 1, 0, 8, 2, rightSegmentTree)low = 0,high = 8,mid = 42 <= 4, so callupdate(1, 1, 0, 4, 2, rightSegmentTree)low = 0,high = 4,mid = 22 <= 2, so callupdate(3, 1, 0, 2, 2, rightSegmentTree)low = 0,high = 2,mid = 12 > 1, so callupdate(8, 1, 2, 2, 2, rightSegmentTree)low = 2,high = 2(leaf node), updaterightSegmentTree[8] += 1
- Update
rightSegmentTree[3] = rightSegmentTree[7] + rightSegmentTree[8] = 0 + 1 = 1
- Update
rightSegmentTree[1] = rightSegmentTree[3] + rightSegmentTree[4] = 1 + 0 = 1
- Update
rightSegmentTree[0] = rightSegmentTree[1] + rightSegmentTree[2] = 1 + 1 = 2
- Call
-
Similarly, process ratings
8,1, and5to get the followingrightSegmentTree:[ 5, 2, 3, 2, 0, 2, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
3. Update Left Segment Tree with First Rating:
- For rating
3(index 0):- Call
update(0, 1, 0, 8, 3, leftSegmentTree)low = 0,high = 8,mid = 43 <= 4, so callupdate(1, 1, 0, 4, 3, leftSegmentTree)low = 0,high = 4,mid = 23 > 2, so callupdate(4, 1, 3, 4, 3, leftSegmentTree)low = 3,high = 4,mid = 33 <= 3, so callupdate(9, 1, 3, 3, 3, leftSegmentTree)low = 3,high = 3(leaf node), updateleftSegmentTree[9] += 1
- Update
leftSegmentTree[4] = leftSegmentTree[9] + leftSegmentTree[10] = 1 + 0 = 1
- Update
leftSegmentTree[1] = leftSegmentTree[3] + leftSegmentTree[4] = 0 + 1 = 1
- Update
leftSegmentTree[0] = leftSegmentTree[1] + leftSegmentTree[2] = 1 + 0 = 1
[ 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] - Call
4. Iterate Through Ratings:
Step for i = 1 (Rating = 6):
Count teams with a lower rating on the left and a higher rating on the right:
-
SumRange for leftLessCount:
- Call
sumRange(0, 5, 0, 8, 0, leftSegmentTree)low = 0,high = 8,mid = 45 <= 4: CallsumRange(0, 5, 0, 4, 1, leftSegmentTree)low = 0,high = 4,mid = 25 > 2: CallsumRange(0, 5, 3, 4, 4, leftSegmentTree)low = 3,high = 4,mid = 35 > 3: CallsumRange(0, 5, 4, 4, 10, leftSegmentTree)low = 4,high = 4(total overlap), return1
leftLessCount = 1
- Call
-
SumRange for rightGreaterCount:
- Call
sumRange(7, 8, 0, 8, 0, rightSegmentTree)low = 0,high = 8,mid = 47 > 4: CallsumRange(7, 8, 5, 8, 2, rightSegmentTree)low = 5,high = 8,mid = 67 > 6: CallsumRange(7, 8, 7, 8, 6, rightSegmentTree)low = 7,high = 8,mid = 77 <= 8: CallsumRange(7, 8, 8, 8, 14, rightSegmentTree)low = 8,high = 8(total overlap), return1
rightGreaterCount = 1
- Call
-
teamCount += 1 * 1 = 1
Count teams with a higher rating on the left and a lower rating on the right:
-
SumRange for leftGreaterCount:
- Call
sumRange(7, 8, 0, 8, 0, leftSegmentTree)low = 0,high = 8,mid = 47 > 4: CallsumRange(7, 8, 5, 8, 2, leftSegmentTree)low = 5,high = 8,mid = 67 > 6: CallsumRange(7, 8, 7, 8, 6, leftSegmentTree)low = 7,high = 8,mid = 77 <= 8: CallsumRange(7, 8, 8, 8, 14, leftSegmentTree)low = 8,high = 8(total overlap), return0
leftGreaterCount = 0
- Call
-
SumRange for rightLessCount:
- Call
sumRange(0, 5, 0, 8, 0, rightSegmentTree)low = 0,high = 8,mid = 45 <= 4: CallsumRange(0, 5, 0, 4, 1, rightSegmentTree)low = 0,high = 4,mid = 25 > 2: CallsumRange(0, 5, 3, 4, 4, rightSegmentTree)low = 3,high = 4,mid = 35 > 3: CallsumRange(0, 5, 4, 4, 10, rightSegmentTree)low = 4,high = 4(total overlap), return1
rightLessCount = 3
- Call
-
teamCount = teamCount + 0 * 3 + 1 + 0 = 1
Update Segment Trees:
- Update
leftSegmentTreeat position6- Call
update(0, 1, 0, 8, 6, leftSegmentTree)
- Call
- Update
rightSegmentTreeat position6- Call
update(0, -1, 0, 8, 6, rightSegmentTree)
- Call
Step for i = 2 (Rating = 2):
-
Count teams with a lower rating on the left and a higher rating on the right:
leftLessCount = sumRange(0, 1, 0, 8, 0, leftSegmentTree) = 0rightGreaterCount = sumRange(3, 8, 0, 8, 0, rightSegmentTree) = 2teamCount = teamCount + 0 * 2 = 1 + 0 = 1
-
Count teams with a higher rating on the left and a lower rating on the right:
leftGreaterCount = sumRange(3, 8, 0, 8, 0, leftSegmentTree) = 2rightLessCount = sumRange(0, 1, 0, 8, 0, rightSegmentTree) = 1teamCount = teamCount + 2 * 1 = 1 + 2 = 3
Update Segment Trees:
- Update
leftSegmentTreeat position2- Call
update(0, 1, 0, 8, 2, leftSegmentTree)
- Call
- Update
rightSegmentTreeat position2- Call
update(0, -1, 0, 8, 2, rightSegmentTree)
- Call
Similarly process other array elements.
Final Output:
teamCount = 3
Code
import java.util.Arrays;
class Solution {
// Update the segment tree at a specific index
public void update(
int index,
int value,
int low,
int high,
int position,
int[] segTree
) {
if (low == high) {
// Base case: Single element
segTree[index] += value; // Update the value at the leaf node
} else {
int mid = (low + high) / 2; // Find the middle point
// If position is in the left subtree
if (position <= mid && position >= low) update(
2 * index + 1,
value,
low,
mid,
position,
segTree
);
else update(2 * index + 2, value, mid + 1, high, position, segTree);
// Update the current node
segTree[index] = segTree[2 * index + 1] + segTree[2 * index + 2];
}
}
// Get the sum range in the segment tree
private int sumRange(
int left,
int right,
int low,
int high,
int index,
int[] segTree
) {
if (low >= left && high <= right) {
// Total overlap
return segTree[index];
}
if (right < low || high < left) {
// No overlap
return 0;
}
int mid = (low + high) / 2; // Partial overlap
// Sum the ranges from both children
return (
sumRange(left, right, low, mid, 2 * index + 1, segTree) +
sumRange(left, right, mid + 1, high, 2 * index + 2, segTree)
);
}
// Main method to count the number of valid teams
public int numTeams(int[] ratings) {
int teamCount = 0; // Initialize team count
int maxRating = Arrays.stream(ratings).max().getAsInt() + 1; // Find max rating
int[] leftSegmentTree = new int[4 * maxRating]; // Segment tree for ratings to the left
int[] rightSegmentTree = new int[4 * maxRating]; // Segment tree for ratings to the right
// Update right segment tree with all ratings except the first
for (int i = 1; i < ratings.length; i++) {
update(0, 1, 0, maxRating - 1, ratings[i], rightSegmentTree);
}
// Update left segment tree with the first rating
update(0, 1, 0, maxRating - 1, ratings[0], leftSegmentTree);
// Iterate through ratings from the second element
for (int i = 1; i < ratings.length; i++) {
// Count teams with a lower rating on the left and a higher rating on the right
int leftLessCount = sumRange(
0,
ratings[i] - 1,
0,
maxRating - 1,
0,
leftSegmentTree
);
int rightGreaterCount = sumRange(
ratings[i] + 1,
maxRating - 1,
0,
maxRating - 1,
0,
rightSegmentTree
);
teamCount += leftLessCount * rightGreaterCount;
// Count teams with a higher rating on the left and a lower rating on the right
int leftGreaterCount = sumRange(
ratings[i] + 1,
maxRating - 1,
0,
maxRating - 1,
0,
leftSegmentTree
);
int rightLessCount = sumRange(
0,
ratings[i] - 1,
0,
maxRating - 1,
0,
rightSegmentTree
);
teamCount += leftGreaterCount * rightLessCount;
// Update the segment trees with the current rating
update(0, 1, 0, maxRating - 1, ratings[i], leftSegmentTree);
update(0, -1, 0, maxRating - 1, ratings[i], rightSegmentTree);
}
return teamCount; // Return the total number of valid teams
}
// Main method to test the solution
public static void main(String[] args) {
Solution solution = new Solution();
// Test case 1
int[] rating1 = { 3, 6, 2, 8, 1, 5 };
int result1 = solution.numTeams(rating1);
System.out.println("Expected Output: 3, Actual Output: " + result1);
// Test case 2
int[] rating2 = { 1, 5, 3, 2, 6, 4 };
int result2 = solution.numTeams(rating2);
System.out.println("Expected Output: 6, Actual Output: " + result2);
// Test case 3
int[] rating3 = { 10, 20, 30, 25, 15 };
int result3 = solution.numTeams(rating3);
System.out.println("Expected Output: 3, Actual Output: " + result3);
}
}
Complexity Analysis
Time Complexity
- Building the Segment Tree: Each update operation on the segment tree takes
time. Since we perform an update for each element in the array, the total time for building the segment tree is . - Querying the Segment Tree: Each range sum query also takes
time. We perform two range sum queries for each element in the array, so the total time for querying is .
Thus, the overall time complexity of the solution is
Space Complexity
- Segment Trees: We use two segment trees, each of size
4 * maxRating. SincemaxRatingis the maximum value in the ratings array incremented by 1, the space complexity for the segment trees is.
Thus, the overall space complexity of the solution is
🤖 Don't fully get this? Learn it with Claude
Stuck on Count Number of Teams? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.
Progressively stronger hints — you still solve it.
I'm working on the problem **Count Number of Teams** (DSA). Give me a HINT LADDER: start with the tiniest nudge, then wait. Only reveal the next, stronger hint when I ask. Do NOT show the full solution unless I type 'show solution'. Keep me doing the thinking. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
See the technique, not just code.
Explain the optimal approach to **Count Number of Teams** with a VISUAL walkthrough: trace it on a small concrete example using ASCII art / a step-by-step diagram, narrate what changes each step, then give time & space complexity with a one-line derivation. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Catch bugs, edge cases, sub-optimality.
I'll paste my solution to **Count Number of Teams**. Review it for correctness, missed edge cases, and time/space complexity, then coach me toward the optimal — don't just rewrite it. Ask me to paste my code now. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Lock in recognition with look-alikes.
Give me 2 problems that use the SAME underlying pattern as **Count Number of Teams**. For each, let me attempt first, then review my answer and name the trigger signal that reveals the pattern. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.