Welcome to Subscribe On Youtube
Formatted question description: https://leetcode.ca/all/1395.html
1395. Count Number of Teams
Level
Medium
Description
There are n
soldiers standing in a line. Each soldier is assigned a unique rating
value.
You have to form a team of 3 soldiers amongst them under the following rules:
 Choose 3 soldiers with index (
i
,j
,k
) with rating (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 number of teams you can form given the conditions. (soldiers can be part of multiple teams).
Example 1:
Input: rating = [2,5,3,4,1]
Output: 3
Explanation: We can form three teams given the conditions. (2,3,4), (5,4,1), (5,3,1).
Example 2:
Input: rating = [2,1,3]
Output: 0
Explanation: We can’t form any team given the conditions.
Example 3:
Input: rating = [1,2,3,4]
Output: 4
Constraints:
n == rating.length
1 <= n <= 200
1 <= rating[i] <= 10^5
Solution
The object of this problem is to find the number of monotone subsequences that have length 3 of the given array rating
. Since the length of rating
does not exceed 200, this problem can be solved by brute force. A solution of dynamic programming also exists.
Consider two cases, where each subsequence is monotonically increasing or monotonically decreasing. First consider the monotonically increasing case. Create an array dp
of length n
, wnere dp[i]
represents the number of elements in subarray rating[0..i  1]
that are less than rating[i]
. Loop over i
from 1 to n  1
. For each i
, loop over j
from i  1
to 0. If rating[i] > rating[j]
, then increase dp[i]
by 1, and at the same time, if dp[j] > 0
, then there exist several elements before j
that are less than rating[j]
, so add dp[j]
to the number of teams. After the loop, the number of teams that are monotically increasing can be obtained.
For the monotonically decrease case, the logic is almost the same except that rating[i] < rating[j]
is used instead of rating[i] > rating[j]
.
Finally, return the number of teams of both cases.

class Solution { public int numTeams(int[] rating) { return numTeams(rating, true) + numTeams(rating, false); } public int numTeams(int[] rating, boolean increase) { int teams = 0; int length = rating.length; int[] dp = new int[length]; for (int i = 1; i < length; i++) { for (int j = i  1; j >= 0; j) { boolean flag = increase ? rating[i] > rating[j] : rating[i] < rating[j]; if (flag) { dp[i]++; if (dp[j] > 0) teams += dp[j]; } } } return teams; } }

class Solution: def numTeams(self, rating: List[int]) > int: n, ans = len(rating), 0 for j in range(1, n  1): ia = ib = ka = kb = 0 for i in range(j): if rating[i] < rating[j]: ia += 1 elif rating[i] > rating[j]: ib += 1 for k in range(j + 1, n): if rating[j] < rating[k]: ka += 1 elif rating[j] > rating[k]: kb += 1 ans += ia * ka + ib * kb return ans

class Solution { public: int numTeams(vector<int>& rating) { int n = rating.size(), ans = 0; for (int j = 1; j < n  1; ++j) { int ia = 0, ib = 0, ka = 0, kb = 0; for (int i = 0; i < j; ++i) { if (rating[i] < rating[j]) ++ia; else if (rating[i] > rating[j]) ++ib; } for (int k = j + 1; k < n; ++k) { if (rating[j] < rating[k]) ++ka; else if (rating[j] > rating[k]) ++kb; } ans += ia * ka + ib * kb; } return ans; } };

func numTeams(rating []int) int { n, ans := len(rating), 0 for j := 1; j < n1; j++ { ia, ib, ka, kb := 0, 0, 0, 0 for i := 0; i < j; i++ { if rating[i] < rating[j] { ia++ } else if rating[i] > rating[j] { ib++ } } for k := j + 1; k < n; k++ { if rating[j] < rating[k] { ka++ } else if rating[j] > rating[k] { kb++ } } ans += ia*ka + ib*kb } return ans }

class BinaryIndexedTree { private n: number; private c: number[]; constructor(n: number) { this.n = n; this.c = new Array(n + 1).fill(0); } public update(x: number, v: number): void { while (x <= this.n) { this.c[x] += v; x += x & x; } } public query(x: number): number { let s = 0; while (x > 0) { s += this.c[x]; x = x & x; } return s; } } function numTeams(rating: number[]): number { let nums = [...rating]; nums.sort((a, b) => a  b); const n = rating.length; let m = 0; for (let i = 0; i < n; ++i) { if (i === 0  nums[i] !== nums[i  1]) { nums[m++] = nums[i]; } } nums = nums.slice(0, m); const search = (x: number): number => { let l = 0; let r = m; while (l < r) { const mid = (l + r) >> 1; if (nums[mid] >= x) { r = mid; } else { l = mid + 1; } } return l + 1; }; let ans = 0; const tree1 = new BinaryIndexedTree(m); const tree2 = new BinaryIndexedTree(m); for (const x of rating) { tree2.update(search(x), 1); } for (let i = 0; i < n; ++i) { const x = search(rating[i]); tree1.update(x, 1); tree2.update(x, 1); const l = tree1.query(x  1); const r = n  i  1  tree2.query(x); ans += l * r; ans += (i  l) * (n  i  1  r); } return ans; }