2024字节青训营笔记(四)游戏队友搜索 | 豆包MarsCode AI刷题

166 阅读5分钟

问题描述

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

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

| 玩家ID | 游戏ID |

问题理解

题目要求在一款多人游戏中,根据玩家和比赛的历史记录,找出与指定玩家至少一起玩过两局比赛的所有玩家。这些玩家被认为是指定玩家的队友。题目提供了一个二维数组,其中每个元素是一个包含两个整数的数组,分别表示玩家ID和比赛ID。我们需要根据这些记录,找出与指定玩家互为队友的所有玩家。

数据结构选择

为了高效地解决这个问题,我们需要选择合适的数据结构来存储和处理数据。以下是几种可能的数据结构及其选择逻辑:

  1. 哈希表(Map)

    • 用途:用于存储每个比赛ID对应的玩家列表。
    • 选择逻辑:由于我们需要快速查找和更新每个比赛ID对应的玩家列表,哈希表是一个理想的选择。哈希表可以在平均O(1)时间内完成插入和查找操作。
  2. 集合(Set)

    • 用途:用于存储指定玩家参与的所有比赛ID。
    • 选择逻辑:集合可以帮助我们快速去重,并且可以在O(1)时间内检查某个比赛ID是否存在。
  3. 计数器(Counter)

    • 用途:用于统计每个玩家与指定玩家一起比赛的次数。
    • 选择逻辑:通过计数器,我们可以快速统计每个玩家与指定玩家一起比赛的次数,从而判断他们是否互为队友。

算法步骤

  1. 初始化数据结构

    • 创建一个哈希表 mp,用于存储每个比赛ID对应的玩家列表。
    • 创建一个集合 np,用于存储指定玩家参与的所有比赛ID。
  2. 遍历输入数组

    • 对于每个记录 [playerID, gameID],如果 playerID 是指定玩家,则将 gameID 添加到集合 np 中。
    • playerID 添加到哈希表 mp 中对应的 gameID 列表中。
  3. 统计队友

    • 创建一个计数器 cnt,用于统计每个玩家与指定玩家一起比赛的次数。
    • 遍历集合 np 中的每个比赛ID,对于每个比赛ID,遍历哈希表 mp 中对应的玩家列表,增加这些玩家在计数器 cnt 中的计数。
  4. 筛选队友

    • 遍历计数器 cnt,找出所有与指定玩家一起比赛次数大于等于2的玩家,并将他们添加到结果列表中。

时间复杂度分析

  • 初始化数据结构:O(1)
  • 遍历输入数组:O(n),其中n是输入数组的长度。
  • 统计队友:O(m * k),其中m是集合 np 的大小,k是每个比赛ID对应的玩家列表的平均长度。
  • 筛选队友:O(p),其中p是计数器 cnt 的大小。

总体时间复杂度为O(n + m * k + p),在大多数情况下,m和k都相对较小,因此算法是高效的。

空间复杂度分析

  • 哈希表 mp:O(n)
  • 集合 np:O(m)
  • 计数器 cnt:O(p)

总体空间复杂度为O(n + m + p),在大多数情况下,n、m和p都相对较小,因此空间复杂度是可以接受的。

cpp代码如下:

std::vector<int> solution(int id, int num, std::vector<std::vector<int>> array) {
    // 用于存储指定玩家参与的所有比赛ID
    set<int> np;

    // 用于存储每个比赛ID对应的玩家列表
    map<int, vector<int>> mp;

    // 遍历输入数组,填充 np 和 mp
    for(auto item : array) {
        int nid = item[0], pid = item[1];
        if(nid == id) {
            // 如果当前玩家ID是指定玩家,则将比赛ID添加到 np 中
            np.insert(pid);
        }
        // 将当前玩家ID添加到对应比赛ID的玩家列表中
        mp[pid].push_back(nid);
    }

    // 用于统计每个玩家与指定玩家一起比赛的次数
    map<int, int> cnt;

    // 遍历指定玩家参与的所有比赛ID
    for(auto x : np) {
        // 遍历每个比赛ID对应的玩家列表
        for(auto item : mp[x]) {
            // 统计每个玩家与指定玩家一起比赛的次数
            cnt[item]++;
        }
    }

    // 用于存储最终结果
    vector<int> ans;

    // 遍历计数器,找出所有与指定玩家一起比赛次数大于等于2的玩家
    for(auto [k, v] : cnt) {
        if(k != id && v >= 2) {
            // 如果玩家不是指定玩家且一起比赛次数大于等于2,则将其添加到结果列表中
            ans.push_back(k);
        }
    }

    // 返回结果列表
    return ans;
}

总结

通过选择合适的数据结构和算法步骤,我们可以高效地解决这个问题。哈希表和集合的使用使得我们能够快速查找和更新数据,而计数器则帮助我们统计每个玩家与指定玩家一起比赛的次数。最终,我们可以通过遍历计数器来筛选出所有符合条件的队友。