← Home

1395. Count Number of Teams

LeetCode article · C++ solution
Website made by wuisabel-gif · Original C++ code by keineahnung2345
two pointersC++Markdown
139

This is one of those problems where the clean idea matters more than the amount of code. For 1395. Count Number of Teams, the solution in this repository is mainly a two pointers solution.

Guide

What?

The first job is to translate the English prompt into state, transition, and stopping conditions. Instead of trying to be clever immediately, read the code as a sequence of questions:

  • What state are we keeping?
  • How do we move from one state to the next?
  • When do we know the answer is already determined?

For this file, the main tools are: two pointers, sliding window, prefix sums, backtracking.

Guide

When?

This pattern shows up when the brute force version has too many repeated checks, too many possible branches, or too much bookkeeping to do by hand. The accepted code reduces that pressure by storing exactly the information that remains useful later.

The important function names to track are isValid, backtrack, numTeams, smaller, update.

Guide

Why?

The point of the implementation is not to make the code longer. It is to avoid doing the same thinking twice.

  • The final return is not magic; it is the invariant after the loops or recursion have finished doing their accounting.

Guide

How?

Walk through the solution in this order:

  1. Start from the smallest reliable state.
  2. Expand one legal move at a time.
  3. Cache, count, or merge information as soon as it becomes settled.
  4. Let the final stored value answer the original question.

The most important competitive-programming habit here is to trust the invariant. Once the invariant is right, the loops become much less scary.

Guide

Complexity

  • Time: O(N^2), space: O(1)
  • Space: O(n) in the usual case for auxiliary containers or recursion

Guide

C++ Solution

Your submission

The accepted solution

solution.cpp
01//Runtime: 344 ms, faster than 5.07% of C++ online submissions for Count Number of Teams.
02//Memory Usage: 7.7 MB, less than 100.00% of C++ online submissions for Count Number of Teams.
03class Solution {
04public:
05    vector<int> rating;
06    int ans;
07    
08    bool isValid(vector<int>& comb){
09        int i = comb[0], j = comb[1], k = comb[2];
10        //0 <= i < j < k < n must hold
11        if(rating[i] > rating[j] && rating[j] > rating[k]){
12            return true;
13        }
14        if(rating[i] < rating[j] && rating[j] < rating[k]){
15            return true;
16        }
17        return false;
18    };
19    
20    void backtrack(vector<int>& comb, int start, int end){
21        if(comb.size() == 3){
22            if(isValid(comb)){
23                ans++;
24            }
25            return;
26        }
27        for(int i = start; end-i+1 >= 3-comb.size(); i++){
28            // cout << "aaa: " << end-i+1 << ", " << 3-comb.size() << endl;
29            // cout << start << ", " << end << endl;
30            comb.push_back(i);
31            backtrack(comb, i+1, end);
32            comb.pop_back();
33        }
34    };
35    
36    int numTeams(vector<int>& rating) {
37        ans = 0;
38        this->rating = rating;
39        
40        vector<int> comb;
41        
42        backtrack(comb, 0, rating.size()-1);
43        
44        return ans;
45    }
46};
47
48//https://leetcode.com/problems/count-number-of-teams/discuss/554795/C%2B%2BJava-O(n-*-n)
49//Runtime: 8 ms, faster than 87.37% of C++ online submissions for Count Number of Teams.
50//Memory Usage: 7.8 MB, less than 100.00% of C++ online submissions for Count Number of Teams.
51//time: O(N^2), space: O(1)
52class Solution {
53public:
54    int numTeams(vector<int>& rating) {
55        int N = rating.size();
56        int ans = 0;
57        
58        for(int i = 1; i < N-1; i++){
59            vector<int> smaller(2), larger(2);
60            
61            for(int j = 0; j < N; j++){
62                //whether j is at the left of i
63                int left = (j < i);
64                if(rating[i] < rating[j]){
65                    smaller[left]++;
66                }
67                if(rating[i] > rating[j]){
68                    larger[left]++;
69                }
70            }
71            
72            ans += smaller[0]*larger[1] + smaller[1]*larger[0];
73        }
74        
75        return ans;
76    }
77};
78
79//Binary Indexed Tree, BIT
80//https://leetcode.com/problems/count-number-of-teams/discuss/554907/Java-Detailed-Explanation-TreeSet-greater-BIT-(Fenwick-Tree)-O(NlogN)
81//Runtime: 16 ms, faster than 73.69% of C++ online submissions for Count Number of Teams.
82//Memory Usage: 55.6 MB, less than 100.00% of C++ online submissions for Count Number of Teams.
83class Solution {
84public:
85    void update(vector<int>& BIT, int idx, int val){
86        while(idx < BIT.size()){
87            BIT[idx] += val;
88            idx += idx & (-idx);
89        }
90    };
91    
92    int getPrefixSum(vector<int>& BIT, int idx){
93        int sum = 0;
94        
95        while(idx > 0){
96            sum += BIT[idx];
97            idx -= idx & (-idx);
98        }
99        
100        return sum;
101    };
102    
103    int getSuffixSum(vector<int>& BIT, int idx){
104        return getPrefixSum(BIT, BIT.size()-1) - getPrefixSum(BIT, idx-1);
105    };
106    
107    int numTeams(vector<int>& rating) {
108        int N = rating.size();
109        if(N < 3) return 0;
110        
111        //rating's range: [1, 1e5]
112        //use rating as index, and count as value
113        vector<int> leftTree(1e5+1, 0);
114        vector<int> rightTree(1e5+1, 0);
115        
116        for(int r : rating){
117            update(rightTree, r, 1);
118        }
119        
120        int ans = 0;
121        
122        //store the count of each rating into rightTree
123        for(int r : rating){
124            //rightTree contains the info of soldiers to the right of current soldier, so we need to remove the info of current soldier from rightTree
125            update(rightTree, r, -1);
126            
127            ans += getPrefixSum(leftTree, r-1)*getSuffixSum(rightTree,r+1);
128            ans += getSuffixSum(leftTree, r+1)*getPrefixSum(rightTree, r-1);
129            
130            //record current soldier's info into leftTree
131            update(leftTree, r, 1);
132        }
133        
134        return ans;
135    }
136};

Cost

Complexity

Time
O(N^2), space: O(1)
Dominated by the main traversal, recursion, or data-structure operations in the code.
Space
O(n) in the usual case for auxiliary containers or recursion
Auxiliary state plus the answer structure where the problem requires one.