ARTICLE · 1039899
京东9月19日机考笔试题与解析
京东9月19日机考笔试题与解析
写在前面
本次给大家带来2026年9月19日京东笔试题的2道题,本场机考题目可在咱们平台上在线刷题。
大厂笔试AI Coding练习:CodeFun2000.com/aicoder-gym
第1题-风控排序评估
题目内容
风控侧要对一批交易做欺诈打分。每笔交易有真实标签 ( 表示正常, 表示欺诈)以及模型给出的风险分 (越大越像欺诈)。
请按 Mann-Whitney U 的秩统计来评估这批打分的排序质量,也就是 AUC。分数相同的交易必须用平均名次,不能随便拆开。
规则如下:
平均名次:把 笔交易按 从小到大排。名次从 起。若连续若干笔分数相同,占住第 到第 个位置,则它们的名次都取 。 由正类名次和还原 AUC:记欺诈笔数为 ,正常笔数为 ,欺诈样本的名次之和为 。令,。
题解
解题思路
AUC 可以不画 ROC,直接用秩统计算。把每笔交易按风险分从小到大排,名次从 起。分数相同的几笔不能拆开,它们合占第 到第 个位置,每笔都记平均名次 。
排序后扫一遍,把同分区间扩满,再把区间内所有下标写成同一个平均名次。 记欺诈笔数为 ,正常笔数为 ,欺诈样本的名次之和为 。若欺诈全部排在最前面,名次和最小是 。多出来的部分 就是正类“赢过”负类的对数(并列计 )。 一共有 对正负样本,因此 。输出必须保留 位小数。 常见假解:并列时按出现顺序硬拆成 ;名次从 起;按分数从大到小编号却仍套同一公式;只统计严格大于、并列不算 。
复杂度分析
时间复杂度:,主要花在按分数排序。,即使用 两两比较也对。 空间复杂度:。
代码实现
python代码(C++和JAVA代码见在线OJ网址)
defauc_from_ranks(labels, scores):""" 标签 1 为欺诈,0 为正常。分数越大越像欺诈。 并列分数占用一段名次区间,区间内每笔都取左右端点的均值。 """ m = len(labels)# 按下标稳定排序,保证同分时相对顺序确定 order = sorted(range(m), key=lambda i: scores[i]) rank = [0.0] * m i = 0while i < m: j = i# 向右扩到同一分数的最后一笔while j + 1 < m and scores[order[j + 1]] == scores[order[i]]: j += 1# 名次从 1 起,区间 [i+1, j+1] avg = (i + 1 + j + 1) / 2.0for k in range(i, j + 1): rank[order[k]] = avg i = j + 1 k_pos = 0 s_pos = 0.0for i in range(m):if labels[i] == 1: k_pos += 1 s_pos += rank[i] k_neg = m - k_pos# U 统计量:正类名次和减去「全排在最前」时的最小名次和 u = s_pos - k_pos * (k_pos + 1) / 2.0return u / (k_pos * k_neg)defmain():# 四级协议:第一行笔数,第二行标签,第三行风险分 m = int(input()) labels = list(map(int, input().split())) scores = list(map(float, input().split())) auc = auc_from_ranks(labels, scores) print("{:.6f}".format(auc))if __name__ == "__main__": main()第2题-四因子乘积对
题目内容
边缘集群里排着 个推理批次,第 个批次带着指纹 。调度会从中任取两个不同批次做成一组,把两个指纹相乘,若乘积的正因子恰好有 个,就记这组为合法组。
同一对批次只算一次,顺序无关。请统计合法组的个数。
题解
解题思路
一个正整数恰好有四个正因子,当且仅当它是某个质数的立方 (因子 ),或两个不同质数之积 (因子 )。
因此两个指纹 合法,只有下面几类:
或 。 乘上质数只有两个因子,不能配质数。 两个不同的质数 。相同质数乘出来是平方,只有三个因子。 ,乘积恰好 。
其余形态( 配 、 配 、合数配合数等)乘积的因子都会多于或少于四个。做法:
筛出 的最小质因子,把每个 拆成质因子。 统计 的个数、 与 的个数、每个质数出现次数、每个 出现次数。 答案为 ,其中 是质数形态的总个数,、 分别是 与 的出现次数。
复杂度分析
时间复杂度:。筛最小质因子 ,每个指纹按最小质因子拆分。 空间复杂度:。主要是筛数组
代码实现
python代码(C++和JAVA代码见在线OJ网址)
MAXB = 1000000defbuild_spf():# 线性筛最小质因子,后面拆指纹用 spf = list(range(MAXB + 1)) i = 2while i * i <= MAXB:if spf[i] == i: j = i * iwhile j <= MAXB:if spf[j] == j: spf[j] = i j += i i += 1return spfdefcount_pairs(vals): spf = build_spf() cnt1 = 0 special = 0 prime_cnt = {} square_cnt = {}for x in vals:if x == 1:# 1 只能和 p^3 或 p*q 配对 cnt1 += 1continue n = x factors = []while n > 1: p = spf[n] c = 0while n % p == 0: n //= p c += 1 factors.append((p, c))if len(factors) == 1: p, c = factors[0]if c == 1: prime_cnt[p] = prime_cnt.get(p, 0) + 1elif c == 2: square_cnt[p] = square_cnt.get(p, 0) + 1elif c == 3: special += 1elif len(factors) == 2and factors[0][1] == 1and factors[1][1] == 1:# 两个不同质数之积 special += 1# 1 与「恰好四因子」的数 ans = cnt1 * special total_p = 0for p, c in prime_cnt.items(): total_p += c# 同一个质数两次乘起来是平方,因子个数不是 4 ans -= c * (c - 1) // 2# p 与 p^2 乘积是 p^3 ans += c * square_cnt.get(p, 0)# 不同质数两两配对 ans += total_p * (total_p - 1) // 2return ansdefmain():# 一行:先 m 再跟 m 个指纹 parts = list(map(int, input().split())) m = parts[0] vals = parts[1 : 1 + m] print(count_pairs(vals))if __name__ == "__main__": main()