给大家分享一下我最近刷的几道题的解析,还有我对 AI 助手的使用心得,这是第一次给大家分享的刷题解析和经验分享,这个系列预计有六期,今天给大家带来第二期的分享。
今天的第一题 —— 根据用户实验命中情况统计符合查询条件的用户数
问题描述
AB 实验作为推荐策略迭代的有力工具,经常会有新的实验上线,以及一些无效策略的下线。在这些迭代过程中,难免会遇到意料之外的情况,导致部分服务崩溃而不可用。为了避免系统的全面崩溃,工程师们会添加监控报警,确保第一时间通知到值班同学进行处理。
小 M 同学刚刚开始负责线上报警的值班工作。很快,她就收到了第一条报警日志。在报警的时间范围内,小 M 同学收到了 N 名用户的反馈,每位用户编号为 1 到 N。小 M 同学查询线上实验后,统计了用户命中实验的列表,其中第 i 位用户命中了 ki 个实验,第 j 个实验的编号为 ai,j。
这些用户的反馈并不完全是由于一个问题造成的,因此小 M 同学需要对这些问题进行分类。根据先前的经验,小 M 同学会进行 Q 次询问尝试对问题进行分类,第 i 次询问会给出一个序列 bi,1,bi,2,…,bi,ci,ci 表示第 i 次查询的实验数量。当 bi,j > 0 时表示命中实验 | bi,j|,否则表示未命中实验 | bi,j|。小 M 同学需要得到符合这些条件的用户数。例如,序列 1, -2, 3 表示命中实验 1, 3 且未命中实验 2 的用户数量。
测试样例
样例 1:
输入:n = 3, m = 3, q = 3, arrayN = [[2, 1, 2], [2, 2, 3], [2, 1, 3]], arrayQ = [[2, 1, -2], [2, 2, -3], [2, 3, -1]]
输出:[1, 1, 1]
样例 2:
输入:n = 5, m = 4, q = 2, arrayN = [[3, 1, 2, 3], [1, 2], [2, 1, 4], [3, 2, 3, 4], [2, 1, 3]], arrayQ = [[3, 1, -4, 2], [2, -1, -3]]
输出:[1, 1]
样例 3:
输入:n = 4, m = 3, q = 2, arrayN = [[1, 1], [2, 2, 3], [1, 3], [2, 1, 2]], arrayQ = [[1, -3], [2, 2, 3]]
输出:[2, 1]
解决方案
要解决这个问题,我们可以按照以下步骤进行:
-
遍历每次查询:
- 对于给定的 Q 次查询,我们需要逐个进行处理。每次查询都有其特定的条件序列,我们要找出符合该查询条件的用户数量。
-
针对每次查询,遍历每个用户:
- 对于当前查询,我们要遍历所有的 N 名用户。查看每个用户的实验命中情况是否符合当前查询的条件。
-
检查用户是否符合查询条件:
-
对于每个用户,我们获取其命中的实验列表。然后针对查询条件序列中的每个实验条件进行检查。
-
对于查询条件序列中的每个元素(表示一个实验条件):
- 首先确定该条件是要求用户命中还是未命中某个实验(根据元素值的正负来判断)。
- 然后在用户的实验命中列表中查找是否满足该条件。如果条件要求命中且未找到匹配实验,或者条件要求未命中但找到了匹配实验,那么该用户就不符合当前查询条件,标记为不符合并跳出对该用户的检查。
-
-
统计符合条件的用户数:
- 如果一个用户通过了所有查询条件的检查,那么就说明该用户符合当前查询条件,将符合条件的用户数量加 1。
-
将符合条件的用户数添加到结果列表:
-
在完成对所有用户的检查后,将此次查询中符合条件的用户数添加到结果列表中。最后返回这个结果列表,其中每个元素对应一次查询中符合条件的用户数。
-
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Main {
public static List<Integer> solution(int n, int m, int q, int[][] arrayN, int[][] arrayQ) {
List<Integer> result = new ArrayList<>();
// 遍历每个查询
for (int i = 0; i < q; i++) {
int count = 0;
int[] query = arrayQ[i];
// 遍历每个用户
for (int j = 0; j < n; j++) {
int[] userExperiments = arrayN[j];
boolean match = true;
// 检查用户是否符合查询条件
for (int k = 1; k < query.length; k++) {
int experiment = query[k];
boolean found = false;
// 检查用户是否命中或未命中实验
for (int l = 1; l < userExperiments.length; l++) {
if (userExperiments[l] == Math.abs(experiment)) {
found = true;
break;
}
}
// 如果查询条件为正数,用户必须命中该实验
// 如果查询条件为负数,用户不能命中该实验
if ((experiment > 0 &&!found) || (experiment < 0 && found)) {
match = false;
break;
}
}
if (match) {
count++;
}
}
// 将符合条件的用户数添加到结果列表中
result.add(count);
}
return result;
}
public static void main(String[] args) {
// Add your test cases here
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)));
}
}
代码功能概述
这段代码主要实现了根据用户的实验命中情况以及给定的查询条件,统计出每次查询中符合条件的用户数量的功能。通过对每个查询依次进行处理,遍历所有用户并检查其是否符合当前查询条件,最后将每次查询符合条件的用户数汇总到结果列表中返回。
代码细节
类定义与函数布局:
-
Main是一个包含solution方法的公开类。solution方法接收多个参数,包括用户数量n、实验数量m、查询次数q以及分别表示用户命中实验情况的二维数组arrayN和表示查询条件的二维数组arrayQ,并返回一个List<Integer>类型的结果列表,其中每个元素是对应一次查询中符合条件的用户数。
字符处理逻辑:
-
在检查用户是否符合查询条件时,通过两层嵌套循环来实现。外层循环遍历查询条件序列中的每个元素(即每个实验条件),内层循环则在用户的实验命中列表中查找是否满足该条件。根据查询条件元素值的正负来判断是要求用户命中还是未命中某个实验,并据此进行相应的匹配判断。
结果拼接与返回:
-
每次查询完成对所有用户的检查后,将符合条件的用户数添加到结果列表
result中。最后直接返回这个结果列表作为最终结果。
核心逻辑
这段代码的核心在于对每个查询条件的准确处理以及对每个用户实验命中情况与查询条件的匹配判断。通过循环遍历的方式,细致地检查每个用户是否满足每次查询的条件,从而准确统计出符合条件的用户数量。由于需要遍历所有的用户和查询条件,算法的时间复杂度为,其中n是用户数量,q是查询次数,m是每个用户命中实验列表的平均长度(假设各用户命中实验数量差异不大)。
总结
这段代码通过合理的循环结构和条件判断,有效地实现了根据用户实验命中情况统计符合查询条件用户数的功能。它清晰地展示了如何处理多组数据之间的关系以及如何根据特定条件进行筛选和统计,这不仅加深了我们对数据处理和条件判断的理解,也让我们看到了在实际应用场景中如何运用这些基本的编程技巧来解决具体问题。
我对 AI 助手的使用心得
在进行这道题的编程与算法学习的过程中,豆包 AI 助手一如既往地成为我重要的解题工具。当我在理解如何根据复杂的用户实验命中情况和查询条件来统计符合条件的用户数时,AI 助手给我提供了清晰的思路和更深入的解释。特别是在分析代码的时间复杂度以及如何优化代码结构等方面,AI 助手都给予了我很大的帮助。它就像是一个知识渊博的导师,随时在我身边为我答疑解惑,助力我在编程之路上不断前进。希望我的这些体会能帮助到同样在编程之路上前行的朋友们!