线上报警问题分类 | 豆包MarsCode AI刷题

30 阅读5分钟

题目概述

  • 在这个问题中,我们有 N 个用户,每个用户可能命中了 M 个不同的实验。

  • 我们会进行 Q 次查询,每次查询会指定一些实验,并尝试找出符合命中或未命中条件的用户数量。

  • 每个查询中给定的条件有两种:

    • 正数实验编号:表示用户必须命中这些实验。
    • 负数实验编号:表示用户不能命中这些实验。

例如:

  • 查询 {2, 1, -2} 表示我们要找出命中了实验 1 但没有命中实验 2 的用户数量。

解题步骤

为了实现这个功能,我们将分以下几个步骤来解题:

  1. 数据存储和初始化

    • 使用一个 HashSet 数组来存储每个用户命中的实验编号。
    • HashSet 是一个方便的工具,可以高效地进行集合操作,例如检查一个元素是否存在。
  2. 处理每次查询

    • 我们需要遍历每个用户,检查用户是否符合查询条件。
    • 每次遍历时,使用查询中的命中/未命中要求,逐一验证用户的实验列表。
  3. 计数符合查询条件的用户数量

    • 通过验证所有用户,找出符合条件的用户并进行计数,最后将结果返回。

代码解释

java复制代码import java.util.*;
​
public class Main {
    public static List<Integer> solution(int n, int m, int q, int[][] arrayN, int[][] arrayQ) {
        // 初始化结果列表
        List<Integer> results = new ArrayList<>();
​
        // 将每个用户的实验命中情况存储在 Set 中
        HashSet<Integer>[] userExperiments = new HashSet[n];  // 使用 HashSet 来存储每个用户命中的实验
        for (int i = 0; i < n; i++) {
            userExperiments[i] = new HashSet<>();
            for (int j = 1; j <= arrayN[i][0]; j++) {
                userExperiments[i].add(arrayN[i][j]);
            }
        }
​
        // 处理每次查询
        for (int i = 0; i < q; i++) {
            int count = 0;
​
            // 遍历所有用户,检查是否符合查询条件
            for (int user = 0; user < n; user++) {
                boolean matches = true;
​
                for (int j = 1; j <= arrayQ[i][0]; j++) {
                    int experiment = arrayQ[i][j];
​
                    if (experiment > 0) {
                        // 检查是否命中实验,如果用户没有命中这个实验则不匹配
                        if (!userExperiments[user].contains(experiment)) {
                            matches = false;
                            break;
                        }
                    } else {
                        // 检查未命中实验,如果用户命中了这个实验则不匹配
                        if (userExperiments[user].contains(-experiment)) {
                            matches = false;
                            break;
                        }
                    }
                }
​
                // 如果当前用户符合所有查询条件,计数加1
                if (matches) {
                    count++;
                }
            }
​
            // 将符合条件的用户数量添加到结果列表中
            results.add(count);
        }
​
        return results;
    }
​
    public static void main(String[] args) {
        // 测试用例
        System.out.println(solution(3, 3, 3, new int[][] { { 2, 1, 2 }, { 2, 2, 3 }, { 2, 1, 3 } },
                new int[][] { { 2, 1, -2 }, { 2, 2, -3 }, { 2, 3, -1 } }).equals(Arrays.asList(1, 1, 1)));
    }
}

代码解析

  1. 初始化用户实验命中情况

    java复制代码HashSet<Integer>[] userExperiments = new HashSet[n];  // 使用 HashSet 来存储每个用户命中的实验
    for (int i = 0; i < n; i++) {
        userExperiments[i] = new HashSet<>();
        for (int j = 1; j <= arrayN[i][0]; j++) {
            userExperiments[i].add(arrayN[i][j]);
        }
    }
    
    • 目的:用 HashSet 存储每个用户命中的实验编号,便于快速查找。
    • 实现细节:遍历 arrayN 来初始化用户的实验命中情况。
    • arrayN[i][0] 表示第 i 个用户命中的实验数量,然后将每个实验编号添加到 HashSet 中。
  2. 处理查询

    java复制代码for (int i = 0; i < q; i++) {
        int count = 0;
    ​
        // 遍历所有用户,检查是否符合查询条件
        for (int user = 0; user < n; user++) {
            boolean matches = true;
    ​
            for (int j = 1; j <= arrayQ[i][0]; j++) {
                int experiment = arrayQ[i][j];
    ​
                if (experiment > 0) {
                    // 检查是否命中实验,如果用户没有命中这个实验则不匹配
                    if (!userExperiments[user].contains(experiment)) {
                        matches = false;
                        break;
                    }
                } else {
                    // 检查未命中实验,如果用户命中了这个实验则不匹配
                    if (userExperiments[user].contains(-experiment)) {
                        matches = false;
                        break;
                    }
                }
            }
    ​
            // 如果当前用户符合所有查询条件,计数加1
            if (matches) {
                count++;
            }
        }
    ​
        // 将符合条件的用户数量添加到结果列表中
        results.add(count);
    }
    
    • 遍历每个用户:对每个用户检查他们是否符合当前的查询条件。

    • 验证条件

      • 对于查询条件中的每个实验编号,正数表示必须命中,负数表示必须未命中。
      • 利用 HashSet 的快速查找特性来检查条件。
    • 匹配用户数量:将符合条件的用户数量存入结果列表。

  3. 输出结果

    • main 函数中,我们通过测试用例来验证解决方案的正确性。

代码运行分析

  • 时间复杂度

    • 用户实验命中情况的初始化:O(N * M),其中 M 是每个用户的实验数量。
    • 每次查询遍历所有用户:O(Q * N * C),其中 C 是每次查询中涉及的实验数量。
    • 因此,时间复杂度为 O(N * M + Q * N * C)
  • 空间复杂度

    • 使用了 O(N)HashSet,每个 HashSet 存储一个用户命中的实验编号。

示例分析

输入:

  • 用户实验数据:

    yaml复制代码用户 1: 命中实验 1, 2
    用户 2: 命中实验 2, 3
    用户 3: 命中实验 1, 3
    
  • 查询数据:

    yaml复制代码查询 1: 命中实验 1, 未命中实验 2 (结果为 1
    查询 2: 命中实验 2, 未命中实验 3 (结果为 1
    查询 3: 命中实验 3, 未命中实验 1 (结果为 1
    

总结

  • 这道题的核心是通过 HashSet 来快速存储和查找用户命中的实验,并通过循环遍历来验证查询条件。
  • 正确地处理命中和未命中条件是这道题的关键所在。
  • 利用集合结构可以有效地加快匹配的速度,从而提高查询效率。