Want Help Cracking FAANG?

(Then click this)

×
Back to Question Bank

1841. League Statistics - Leetcode Solution

Code Implementation

from collections import defaultdict
class Solution:
    def leagueStatistics(self, matches):
        stats = defaultdict(lambda: {'games':0, 'wins':0, 'loses':0, 'draws':0, 'points':0})
        for match in matches:
            team1, team2, score1, score2 = match
            stats[team1]['games'] += 1
            stats[team2]['games'] += 1
            if score1 > score2:
                stats[team1]['wins'] += 1
                stats[team2]['loses'] += 1
                stats[team1]['points'] += 3
            elif score1 < score2:
                stats[team2]['wins'] += 1
                stats[team1]['loses'] += 1
                stats[team2]['points'] += 3
            else:
                stats[team1]['draws'] += 1
                stats[team2]['draws'] += 1
                stats[team1]['points'] += 1
                stats[team2]['points'] += 1
        result = []
        for team in sorted(stats.keys()):
            s = stats[team]
            result.append([team, s['games'], s['wins'], s['loses'], s['draws'], s['points']])
        return result
      
#include <vector>
#include <string>
#include <unordered_map>
#include <map>
using namespace std;
class Solution {
public:
    vector<vector<int>> leagueStatistics(vector<vector<string>>& matches) {
        map<string, vector<int>> stats;
        for (auto& match : matches) {
            string team1 = match[0], team2 = match[1];
            int score1 = stoi(match[2]), score2 = stoi(match[3]);
            if (!stats.count(team1)) stats[team1] = vector<int>(5, 0);
            if (!stats.count(team2)) stats[team2] = vector<int>(5, 0);
            stats[team1][0]++; stats[team2][0]++;
            if (score1 > score2) {
                stats[team1][1]++;
                stats[team2][2]++;
                stats[team1][4] += 3;
            } else if (score1 < score2) {
                stats[team2][1]++;
                stats[team1][2]++;
                stats[team2][4] += 3;
            } else {
                stats[team1][3]++; stats[team2][3]++;
                stats[team1][4]++; stats[team2][4]++;
            }
        }
        vector<vector<int>> result;
        for (auto& p : stats) {
            vector<int> row = {p.second[0], p.second[1], p.second[2], p.second[3], p.second[4]};
            row.insert(row.begin(), 0); // Placeholder for team name index
            result.push_back(row);
        }
        return result;
    }
};
      
import java.util.*;
class Solution {
    public List<List<Object>> leagueStatistics(List<List<Object>> matches) {
        Map<String, int[]> stats = new TreeMap<>();
        for (List<Object> match : matches) {
            String team1 = (String)match.get(0), team2 = (String)match.get(1);
            int score1 = (int)match.get(2), score2 = (int)match.get(3);
            stats.putIfAbsent(team1, new int[5]);
            stats.putIfAbsent(team2, new int[5]);
            stats.get(team1)[0]++;
            stats.get(team2)[0]++;
            if (score1 > score2) {
                stats.get(team1)[1]++;
                stats.get(team2)[2]++;
                stats.get(team1)[4] += 3;
            } else if (score1 < score2) {
                stats.get(team2)[1]++;
                stats.get(team1)[2]++;
                stats.get(team2)[4] += 3;
            } else {
                stats.get(team1)[3]++;
                stats.get(team2)[3]++;
                stats.get(team1)[4]++;
                stats.get(team2)[4]++;
            }
        }
        List<List<Object>> result = new ArrayList<>();
        for (String team : stats.keySet()) {
            int[] s = stats.get(team);
            List<Object> row = Arrays.asList(team, s[0], s[1], s[2], s[3], s[4]);
            result.add(row);
        }
        return result;
    }
}
      
function leagueStatistics(matches) {
    const stats = {};
    for (const match of matches) {
        const [team1, team2, score1, score2] = match;
        if (!stats[team1]) stats[team1] = [0,0,0,0,0];
        if (!stats[team2]) stats[team2] = [0,0,0,0,0];
        stats[team1][0]++; stats[team2][0]++;
        if (score1 > score2) {
            stats[team1][1]++;
            stats[team2][2]++;
            stats[team1][4] += 3;
        } else if (score1 < score2) {
            stats[team2][1]++;
            stats[team1][2]++;
            stats[team2][4] += 3;
        } else {
            stats[team1][3]++; stats[team2][3]++;
            stats[team1][4]++; stats[team2][4]++;
        }
    }
    return Object.keys(stats).sort().map(team => [team, ...stats[team]]);
}
      

Problem Description

You are given a list of football (soccer) matches, where each match is represented as a list or array containing team1, team2, score1, and score2. Your task is to compute league statistics for each team and output, for every team that played at least one match, the following statistics:

  • Total games played
  • Total wins
  • Total losses
  • Total draws
  • Total points (3 for a win, 1 for a draw, 0 for a loss)

Each team should be listed in lexicographical (alphabetical) order. Each match involves two teams, and scores are non-negative integers. No team will play itself. There is only one valid way to compute the statistics, and each match is considered only once.

Thought Process

To solve this problem, we need to track various statistics for each team as we process each match. The brute-force approach would be to scan through all matches for each team, but this would be inefficient. Instead, we can use a hash map (dictionary) to accumulate statistics as we iterate through the matches just once. This way, we avoid redundant work and ensure that all teams' stats are updated in real time.

The key realization is that both teams in each match are affected, so we must update both teams' records simultaneously. Using a dictionary with the team name as the key allows us to efficiently store and update each team's statistics.

Solution Approach

  • Step 1: Initialize a dictionary (hash map) to store each team's statistics. The value for each team will be a structure (like a list or object) holding counts for games, wins, losses, draws, and points.
  • Step 2: Iterate through each match in the input list. For each match:
    • Extract team1, team2, score1, and score2.
    • If a team is not yet in the dictionary, add it with zeroed stats.
    • Increment the games played for both teams.
    • Compare the scores:
      • If score1 > score2: team1 wins (add win and points), team2 loses.
      • If score1 < score2: team2 wins, team1 loses.
      • If equal: both teams draw (add draw and points).
  • Step 3: After all matches are processed, collect the results for each team. Sort the teams alphabetically and output their statistics in the required format.

This approach ensures each match is processed only once, and updates for both teams are handled together, making it efficient and reliable.

Example Walkthrough

Suppose we have the following input:

  • [["Alpha", "Beta", 2, 1], ["Beta", "Gamma", 0, 0], ["Gamma", "Alpha", 1, 3]]

Let's process each match:

  1. Match 1: Alpha 2 - 1 Beta
    • Alpha: +1 game, +1 win, +3 points
    • Beta: +1 game, +1 loss
  2. Match 2: Beta 0 - 0 Gamma
    • Beta: +1 game, +1 draw, +1 point
    • Gamma: +1 game, +1 draw, +1 point
  3. Match 3: Gamma 1 - 3 Alpha
    • Gamma: +1 game, +1 loss
    • Alpha: +1 game, +1 win, +3 points

Final stats (sorted alphabetically):

  • Alpha: 2 games, 2 wins, 0 losses, 0 draws, 6 points
  • Beta: 2 games, 0 wins, 1 loss, 1 draw, 1 point
  • Gamma: 2 games, 0 wins, 1 loss, 1 draw, 1 point

Time and Space Complexity

Brute-force approach: For each team, scan all matches to accumulate stats. If there are n matches and t teams, this is O(n * t).

Optimized approach: We process each match once (O(n)), and for each match, update both teams in O(1) time. Sorting the teams at the end takes O(t \log t). Thus, the total time is O(n + t \log t).

Space complexity: We store stats for each team, so O(t) space.

Summary

The problem is solved efficiently by using a hash map to store and update each team's statistics as we process each match. This approach avoids redundant work and keeps the code clean and readable. By sorting the teams at the end, we meet the output requirements. The use of a single pass through the matches and constant-time updates for each team makes this solution both elegant and optimal for large inputs.