游戏中的队友关系:如何高效找到你的游戏战友 | 豆包MarsCode AI刷题

164 阅读3分钟

前言

如果你玩过多人在线游戏,一定会遇到这样的场景:某局游戏里你和几位玩家默契配合,之后你想知道这些人是否是你的“长期队友”。在算法的世界里,这样的关系判断问题可以通过巧妙的设计高效解决!今天,我们结合一道豆包MarsCode的趣味题,探索如何找出一位玩家的所有“长期队友”。


问题背景与挑战

游戏的参与记录是由玩家ID游戏ID构成的二维数据集。如果两个玩家在至少两局游戏中同时出现,他们就被认为是彼此的队友。问题在于:

  1. 海量数据:玩家和游戏的数量可能高达数百万级。
  2. 高效计算:如何快速找到某玩家的所有队友?
  3. 结果排序:输出结果需要按升序排列。

让我们用一个实际的案例来说明:

image.png

image.png

image.png

解题思路解析

为了高效解决这个问题,我们需要以下步骤:

  1. 构建玩家-游戏映射:用一个哈希表将每个玩家和他参与过的游戏进行关联。

  2. 查找目标玩家的游戏集合:确定指定玩家玩过的所有游戏。

  3. 遍历其他玩家,计算游戏交集

    • 如果某玩家与目标玩家的游戏交集数量大于等于2,则判定为队友。
  4. 结果排序:将队友ID按升序排序,输出结果。

算法核心:集合操作与交集计算

我们用一个 HashMap 存储玩家与游戏的对应关系,借助集合的交集操作快速判断是否满足队友条件。这种方法充分利用了集合操作的效率,避免了暴力解法的低效。

以下是完整的代码实现:

Java代码实现

import java.util.*;

public class Main {
    public static void main(String[] args) {
        // 测试输入
        Scanner scanner = new Scanner(System.in);

        // 读取目标玩家ID
        int id = Integer.parseInt(scanner.nextLine());

        // 读取记录数量
        int num = Integer.parseInt(scanner.nextLine());

        // 读取玩家与游戏记录
        int[][] records = new int[num][2];
        for (int i = 0; i < num; i++) {
            String[] parts = scanner.nextLine().split(" ");
            records[i][0] = Integer.parseInt(parts[0]);
            records[i][1] = Integer.parseInt(parts[1]);
        }

        // 计算队友
        int[] result = solution(id, num, records);

        // 输出队友列表
        System.out.println(Arrays.toString(result).replaceAll("[\[\],]", ""));
    }

    public static int[] solution(int id, int num, int[][] array) {
        // 玩家游戏记录的 Map
        Map<Integer, Set<Integer>> playerGamesMap = new HashMap<>();

        // 构建玩家游戏记录
        for (int[] record : array) {
            int playerId = record[0];
            int gameId = record[1];

            playerGamesMap.putIfAbsent(playerId, new HashSet<>());
            playerGamesMap.get(playerId).add(gameId);
        }

        // 获取指定玩家参与的游戏集合
        Set<Integer> targetPlayerGames = playerGamesMap.getOrDefault(id, new HashSet<>());

        // 结果集合
        List<Integer> teammates = new ArrayList<>();

        // 遍历其他玩家
        for (Map.Entry<Integer, Set<Integer>> entry : playerGamesMap.entrySet()) {
            int otherPlayerId = entry.getKey();
            Set<Integer> otherPlayerGames = entry.getValue();

            // 跳过目标玩家自身
            if (otherPlayerId == id) continue;

            // 计算交集
            Set<Integer> intersection = new HashSet<>(targetPlayerGames);
            intersection.retainAll(otherPlayerGames);

            // 判断交集数量是否 >= 2
            if (intersection.size() >= 2) {
                teammates.add(otherPlayerId);
            }
        }

        // 对结果进行升序排序
        Collections.sort(teammates);

        // 转为数组返回
        return teammates.stream().mapToInt(Integer::intValue).toArray();
    }
}

代码解析

构建玩家-游戏映射

通过遍历记录,将每个玩家与他参与的游戏存入 HashMap 中。
例如,记录 1 1 会将玩家 1 加入 Map,并关联到游戏 1

for (int[] record : array) {
    int playerId = record[0];
    int gameId = record[1];

    playerGamesMap.putIfAbsent(playerId, new HashSet<>());
    playerGamesMap.get(playerId).add(gameId);
}

查找队友逻辑

对每位玩家,与目标玩家的游戏集合求交集,判断交集的大小是否大于等于2。如果满足条件,则将该玩家加入队友列表:

Set<Integer> intersection = new HashSet<>(targetPlayerGames);
intersection.retainAll(otherPlayerGames);
if (intersection.size() >= 2) {
    teammates.add(otherPlayerId);
}

排序输出

队友列表需要按升序输出,因此在将结果添加至列表后,用 Collections.sort() 排序。

总结

通过豆包MarsCode平台的实战,我们学会了如何用集合操作解决实际问题,感受到了算法的优雅与高效。如果你正在寻找既有趣又实用的算法题目,这个平台会是一个非常好的选择。

思考延伸:

  • 如果要求找到参与同一游戏最多的玩家组合,你会如何设计算法?
  • 在分布式环境中,如何优化大规模数据的交集计算?

期待在豆包MarsCode的学习路上和大家继续交流与成长!