题目解析与学习总结:游戏队友搜索 | 豆包MarsCode AI刷题

128 阅读3分钟

题目描述

在一款多人游戏中,每局比赛需要多个玩家参与。如果发现两名玩家至少一起玩过两局比赛,则可以认为这两名玩家互为队友。现在你有一份玩家(通过玩家ID标识)和比赛局次(通过比赛ID标识)的历史记录表,目标是帮助某位指定玩家找到所有符合条件的队友。

例如,已知以下比赛历史记录:

题目解析

1. 分析题目需求:

每名玩家用玩家ID标识,每局比赛用比赛ID标识。

历史记录表包含玩家ID和比赛ID的关联信息。

对于指定玩家 ididid,需要找出所有至少一起玩过两局比赛的玩家ID。

2. 算法思路:

分组匹配:

首先找到目标玩家 ididid 所参加的比赛ID集合。

遍历历史记录表,记录每名玩家参与的比赛ID集合。

统计交集:

对每名玩家,计算其比赛集合与目标玩家比赛集合的交集大小。

如果交集大小大于等于2,则该玩家为目标玩家的队友。

3. 数据结构:

使用 Map<Integer, Set> 保存每个玩家参与的比赛ID集合。

使用 Set 便于快速计算比赛集合的交集。

代码实现(JAVA):

import java.util.*;
public class Main {
public static void main(String[] args) {
    // 测试用例1
    System.out.println(
            Arrays.equals(
                    solution(1, 10,
                            new int[][] {
                                    { 1, 1 }, { 1, 2 }, { 1, 3 }, { 2, 1 }, { 2, 4 }, { 3, 2 },
                                    { 4, 1 }, { 4, 2 }, { 5, 2 }, { 5, 3 }
                            }),
                    new int[] { 4, 5 }));

    // 测试用例2
    System.out.println(
            Arrays.equals(
                    solution(2, 6,
                            new int[][] {
                                    { 2, 1 }, { 2, 3 }, { 1, 1 }, { 1, 2 }, { 3, 1 }, { 4, 3 }
                            }),
                    new int[] {}));

    // 测试用例3
    System.out.println(
            Arrays.equals(
                    solution(3, 8,
                            new int[][] {
                                    { 3, 1 }, { 3, 2 }, { 3, 3 }, { 4, 1 }, { 5, 2 }, { 6, 3 },
                                    { 7, 1 }, { 7, 2 }
                            }),
                    new int[] { 7 }));
}

public static int[] solution(int id, int num, int[][] array) {
    // 1. 创建玩家ID到比赛ID集合的映射
    Map<Integer, Set<Integer>> playerGames = new HashMap<>();
    for (int[] record : array) {
        int playerId = record[0];
        int gameId = record[1];
        playerGames.putIfAbsent(playerId, new HashSet<>());
        playerGames.get(playerId).add(gameId);
    }

    // 2. 获取目标玩家的比赛ID集合
    Set<Integer> targetGames = playerGames.getOrDefault(id, Collections.emptySet());
    if (targetGames.isEmpty()) {
        return new int[] {}; // 如果目标玩家没有记录,直接返回空
    }

    // 3. 找到所有符合条件的队友
    List<Integer> teammates = new ArrayList<>();
    for (Map.Entry<Integer, Set<Integer>> entry : playerGames.entrySet()) {
        int playerId = entry.getKey();
        Set<Integer> games = entry.getValue();

        // 跳过目标玩家自己
        if (playerId == id) {
            continue;
        }

        // 计算交集大小
        Set<Integer> intersection = new HashSet<>(games);
        intersection.retainAll(targetGames);

        if (intersection.size() >= 2) {
            teammates.add(playerId);
        }
    }

    // 4. 返回队友列表,按玩家ID排序
    Collections.sort(teammates);
    return teammates.stream().mapToInt(Integer::intValue).toArray();
}

}

代码详解

1. 玩家比赛映射:

遍历输入数组 array,将每个玩家的比赛记录存入 Map<Integer, Set> 中。

2. 目标玩家比赛集合:

从映射中获取目标玩家 ididid 的比赛集合 targetGames。

若目标玩家无比赛记录,直接返回空结果。

3. 交集计算:

对于每名玩家,计算其比赛集合与 targetGames 的交集大小。

使用 retainAll 方法简化交集计算。

4. 结果处理:

将满足条件的玩家ID加入列表 teammates。

对结果列表排序,并转换为数组返回。

 

个人思考与分析

1. 难点解析:

交集计算: 如何高效计算玩家比赛集合的交集是本题的核心问题。通过 HashSet 的 retainAll 方法,可以轻松实现交集计算。

性能优化: 为了减少不必要的计算,通过映射预处理玩家数据,将遍历与交集计算的复杂度降低。

2. 算法适用场景:

  本题的方法可以推广到类似社交网络中的好友关系计算问题,如“共同好友”或“共同兴趣”。

3. 个人收获:

通过本题目,熟悉了使用 HashSet 和 Map 进行复杂关系映射和交集运算对解决“交集型”问题的思路有了更深刻的理解