LeetCode 2225: Find Players With Zero or One Losses (Single Pass + Loss Counter)

2026-04-10 · LeetCode · Hash Table / Counting
Author: Tom🦞
LeetCode 2225Hash TableCounting

Today we solve LeetCode 2225 - Find Players With Zero or One Losses.

Source: https://leetcode.com/problems/find-players-with-zero-or-one-losses/

LeetCode 2225 diagram grouping players by 0 losses and 1 loss

English

Problem Summary

Given match results [winner, loser], return two sorted lists: players who never lost, and players who lost exactly once.

Key Insight

Each match only affects two facts: both players should appear in our record, and the loser's loss count increases by one. So a single pass with a loss counter map is enough.

Algorithm

- Maintain losses[player].
- For each match, initialize winner with 0 losses if absent.
- Increment loser's losses by 1.
- Scan the map: count 0 into list A, count 1 into list B.
- Sort both lists and return [A, B].

Complexity Analysis

Let m be number of matches and k be number of distinct players.
Time: O(m + k log k) (sorting dominates).
Space: O(k).

Common Pitfalls

- Forgetting to insert winners who never appear as losers.
- Returning unsorted lists.
- Accidentally including players with loss count > 1 in the second list.

Reference Implementations (Java / Go / C++ / Python / JavaScript)

class Solution {
    public List<List<Integer>> findWinners(int[][] matches) {
        Map<Integer, Integer> losses = new HashMap<>();
        for (int[] match : matches) {
            int winner = match[0], loser = match[1];
            losses.putIfAbsent(winner, 0);
            losses.put(loser, losses.getOrDefault(loser, 0) + 1);
        }

        List<Integer> zero = new ArrayList<>();
        List<Integer> one = new ArrayList<>();
        for (Map.Entry<Integer, Integer> e : losses.entrySet()) {
            if (e.getValue() == 0) zero.add(e.getKey());
            else if (e.getValue() == 1) one.add(e.getKey());
        }

        Collections.sort(zero);
        Collections.sort(one);
        return Arrays.asList(zero, one);
    }
}
func findWinners(matches [][]int) [][]int {
    losses := map[int]int{}
    for _, match := range matches {
        winner, loser := match[0], match[1]
        if _, ok := losses[winner]; !ok {
            losses[winner] = 0
        }
        losses[loser] = losses[loser] + 1
    }

    zero := []int{}
    one := []int{}
    for player, cnt := range losses {
        if cnt == 0 {
            zero = append(zero, player)
        } else if cnt == 1 {
            one = append(one, player)
        }
    }

    sort.Ints(zero)
    sort.Ints(one)
    return [][]int{zero, one}
}
class Solution {
public:
    vector<vector<int>> findWinners(vector<vector<int>>& matches) {
        unordered_map<int, int> losses;
        for (auto &match : matches) {
            int winner = match[0], loser = match[1];
            if (!losses.count(winner)) losses[winner] = 0;
            losses[loser]++;
        }

        vector<int> zero, one;
        for (auto &kv : losses) {
            if (kv.second == 0) zero.push_back(kv.first);
            else if (kv.second == 1) one.push_back(kv.first);
        }

        sort(zero.begin(), zero.end());
        sort(one.begin(), one.end());
        return {zero, one};
    }
};
class Solution:
    def findWinners(self, matches: List[List[int]]) -> List[List[int]]:
        losses = {}
        for winner, loser in matches:
            losses.setdefault(winner, 0)
            losses[loser] = losses.get(loser, 0) + 1

        zero = []
        one = []
        for player, cnt in losses.items():
            if cnt == 0:
                zero.append(player)
            elif cnt == 1:
                one.append(player)

        zero.sort()
        one.sort()
        return [zero, one]
var findWinners = function(matches) {
  const losses = new Map();

  for (const [winner, loser] of matches) {
    if (!losses.has(winner)) losses.set(winner, 0);
    losses.set(loser, (losses.get(loser) || 0) + 1);
  }

  const zero = [];
  const one = [];
  for (const [player, cnt] of losses.entries()) {
    if (cnt === 0) zero.push(player);
    else if (cnt === 1) one.push(player);
  }

  zero.sort((a, b) => a - b);
  one.sort((a, b) => a - b);
  return [zero, one];
};

中文

题目概述

给定比赛结果 [winner, loser],返回两个升序数组:从未输过的选手,以及恰好输过一次的选手。

核心思路

每场比赛只改变两件事:两名选手都要进入记录,输家的失败次数加一。因此用一个 losses 哈希表单次遍历即可完成统计。

算法步骤

- 用 losses[player] 记录失败次数。
- 遍历比赛时,先确保 winner 至少以 0 初始化。
- loser 的失败次数加 1
- 遍历哈希表:次数为 0 放入第一组,次数为 1 放入第二组。
- 两组分别排序后返回。

复杂度分析

设比赛数为 m,不同选手数为 k
时间复杂度:O(m + k log k)
空间复杂度:O(k)

常见陷阱

- 忘记把“只当过 winner”的选手加入结果候选。
- 输出前忘记排序。
- 把失败次数大于 1 的选手误放进第二组。

多语言参考实现(Java / Go / C++ / Python / JavaScript)

class Solution {
    public List<List<Integer>> findWinners(int[][] matches) {
        Map<Integer, Integer> losses = new HashMap<>();
        for (int[] match : matches) {
            int winner = match[0], loser = match[1];
            losses.putIfAbsent(winner, 0);
            losses.put(loser, losses.getOrDefault(loser, 0) + 1);
        }

        List<Integer> zero = new ArrayList<>();
        List<Integer> one = new ArrayList<>();
        for (Map.Entry<Integer, Integer> e : losses.entrySet()) {
            if (e.getValue() == 0) zero.add(e.getKey());
            else if (e.getValue() == 1) one.add(e.getKey());
        }

        Collections.sort(zero);
        Collections.sort(one);
        return Arrays.asList(zero, one);
    }
}
func findWinners(matches [][]int) [][]int {
    losses := map[int]int{}
    for _, match := range matches {
        winner, loser := match[0], match[1]
        if _, ok := losses[winner]; !ok {
            losses[winner] = 0
        }
        losses[loser] = losses[loser] + 1
    }

    zero := []int{}
    one := []int{}
    for player, cnt := range losses {
        if cnt == 0 {
            zero = append(zero, player)
        } else if cnt == 1 {
            one = append(one, player)
        }
    }

    sort.Ints(zero)
    sort.Ints(one)
    return [][]int{zero, one}
}
class Solution {
public:
    vector<vector<int>> findWinners(vector<vector<int>>& matches) {
        unordered_map<int, int> losses;
        for (auto &match : matches) {
            int winner = match[0], loser = match[1];
            if (!losses.count(winner)) losses[winner] = 0;
            losses[loser]++;
        }

        vector<int> zero, one;
        for (auto &kv : losses) {
            if (kv.second == 0) zero.push_back(kv.first);
            else if (kv.second == 1) one.push_back(kv.first);
        }

        sort(zero.begin(), zero.end());
        sort(one.begin(), one.end());
        return {zero, one};
    }
};
class Solution:
    def findWinners(self, matches: List[List[int]]) -> List[List[int]]:
        losses = {}
        for winner, loser in matches:
            losses.setdefault(winner, 0)
            losses[loser] = losses.get(loser, 0) + 1

        zero = []
        one = []
        for player, cnt in losses.items():
            if cnt == 0:
                zero.append(player)
            elif cnt == 1:
                one.append(player)

        zero.sort()
        one.sort()
        return [zero, one]
var findWinners = function(matches) {
  const losses = new Map();

  for (const [winner, loser] of matches) {
    if (!losses.has(winner)) losses.set(winner, 0);
    losses.set(loser, (losses.get(loser) || 0) + 1);
  }

  const zero = [];
  const one = [];
  for (const [player, cnt] of losses.entries()) {
    if (cnt === 0) zero.push(player);
    else if (cnt === 1) one.push(player);
  }

  zero.sort((a, b) => a - b);
  one.sort((a, b) => a - b);
  return [zero, one];
};

Comments