游戏队友搜索 | 豆包MarsCode AI刷题

5 阅读4分钟

问题描述

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

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

| 玩家ID | 游戏ID |

测试样例

样例1:

输入:id = 1, num = 10, array = [[1,1], [1,2], [1,3], [2,1], [2,4], [3,2], [4,1], [4,2], [5,2], [5,3]]
输出:[4, 5]

样例2:

输入:id = 2, num = 6, array = [[2,1], [2,3], [1,1], [1,2], [3,1], [4,3]]
输出:[]

样例3:

输入:id = 3, num = 8, array = [[3,1], [3,2], [3,3], [4,1], [5,2], [6,3], [7,1], [7,2]]
输出:[7]

详细解析与思路

这道题目涉及 数据处理与映射关系的管理,需要通过分析游戏历史记录,找到符合条件的队友。以下是逐步解析思路和关键步骤:

问题分析

  1. 题目核心

    • 给定玩家 id 和历史记录表,找到至少和该玩家同场玩过 两局及以上 的其他玩家。
  2. 解法关键

    • 每场游戏玩家分组:通过比赛 ID 找到每局比赛的玩家。
    • 统计队友频率:统计与指定玩家一起玩过的玩家及其共同参与的比赛次数。
    • 筛选有效队友:只保留共同比赛次数 >= 2 的玩家。

知识总结与思路整理

  1. 数据结构的选择

    • std::unordered_map:用于记录每个游戏 ID 对应的玩家集合。它提供 O(1) 的插入和查找效率,非常适合这种需要快速定位数据的场景。
    • std::unordered_set:存储每场比赛的玩家,避免重复,方便统计。
  2. 算法步骤分解

    1. 遍历输入的比赛记录,将每场比赛的玩家归类到对应的比赛 ID。
    2. 检查目标玩家是否参与某场比赛,记录与目标玩家共同参赛的玩家及其次数。
    3. 筛选符合条件的玩家(出现次数 >= 2),并按升序排序。

代码详解

#include <iostream>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <algorithm>

// 主函数:根据指定玩家ID,找到符合条件的队友
std::vector<int> solution(int id, int num, std::vector<std::vector<int>> array) {
    // 1. 将每场比赛的玩家集合记录到 gameToPlayers 映射中
    std::unordered_map<int, std::unordered_set<int>> gameToPlayers;
    for (const auto& entry : array) {
        int playerID = entry[0]; // 玩家ID
        int gameID = entry[1];   // 游戏ID
        gameToPlayers[gameID].insert(playerID); // 玩家加入对应的游戏集合
    }

    // 2. 统计与目标玩家一起玩的玩家次数
    std::unordered_map<int, int> teammateCount;
    for (const auto& [gameID, players] : gameToPlayers) {
        if (players.count(id)) { // 如果目标玩家参与了这局游戏
            for (int player : players) { // 遍历同场玩家
                if (player != id) { // 排除目标玩家自身
                    teammateCount[player]++; // 计数 +1
                }
            }
        }
    }

    // 3. 找到符合条件的队友(出现次数 >= 2),并保存到结果
    std::vector<int> result;
    for (const auto& [player, count] : teammateCount) {
        if (count >= 2) { // 队友条件判断
            result.push_back(player);
        }
    }

    // 4. 按升序排序队友ID
    std::sort(result.begin(), result.end());
    return result;
}

int main() {
    // 测试样例1
    std::vector<int> result1 = solution(1, 10, {{1, 1}, {1, 2}, {1, 3}, {2, 1}, {2, 4}, {3, 2}, {4, 1}, {4, 2}, {5, 2}, {5, 3}});
    for (int player : result1) {
        std::cout << player << " ";
    }
    std::cout << std::endl;

    // 测试样例2
    std::vector<int> result2 = solution(2, 6, {{2, 1}, {2, 3}, {1, 1}, {1, 2}, {3, 1}, {4, 3}});
    for (int player : result2) {
        std::cout << player << " ";
    }
    std::cout << std::endl;

    // 测试样例3
    std::vector<int> result3 = solution(3, 8, {{3, 1}, {3, 2}, {3, 3}, {4, 1}, {5, 2}, {6, 3}, {7, 1}, {7, 2}});
    for (int player : result3) {
        std::cout << player << " ";
    }
    std::cout << std::endl;

    return 0;
}

代码运行过程解析

以样例1为例:

输入:

玩家ID = 1,比赛记录表:

[[1, 1], [1, 2], [1, 3], [2, 1], [2, 4], [3, 2], [4, 1], [4, 2], [5, 2], [5, 3]]
Step 1:构建游戏玩家映射

创建 gameToPlayers

1: {1, 2, 4}
2: {1, 3, 4, 5}
3: {1, 5}
4: {2}
Step 2:统计与目标玩家的共同比赛次数

目标玩家 1 参与了游戏 1, 2, 3

  • 游戏 1:玩家 {2, 4},计数为 {2: 1, 4: 1}
  • 游戏 2:玩家 {3, 4, 5},计数为 {2: 1, 4: 2, 3: 1, 5: 1}
  • 游戏 3:玩家 {5},计数为 {2: 1, 4: 2, 3: 1, 5: 2}
Step 3:筛选符合条件的队友

队友条件:计数 ≥ 2,结果为 {4, 5}

Step 4:排序结果

最终输出:[4, 5]

对入门同学的学习建议

  1. 理解题意与数据处理逻辑

    • 分析题目需求,明确核心目标是统计玩家间的共同参赛次数。
    • 划分问题步骤,通过多层数据结构(unordered_mapunordered_set)组织数据,降低复杂度。
  2. 掌握 STL 容器的应用

    • 学会使用 unordered_mapunordered_set 来高效存储和查找数据。
    • 使用 std::sort 对结果排序,注意算法的时间复杂度。
  3. 分解与调试代码

    • 将问题分解成小任务,例如先构建映射、统计次数、再筛选和排序。
    • 利用调试工具逐步验证数据流是否正确,特别是多层嵌套的循环和逻辑判断。
  4. 代码优化与可读性

    • 为关键变量和数据结构命名,增加注释,方便自己和他人阅读。
    • 尝试优化逻辑,减少不必要的计算。