news 2026/9/19 13:27:38

数据分析师笔试题解析:异常值、聚类、SQL与AB测试实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
数据分析师笔试题解析:异常值、聚类、SQL与AB测试实战

简介:这份《数据分析笔试题》PDF是一份面向数据分析师求职与技能自测的练习资料,内容取自互联网公司真实笔试场景,涵盖统计学基础、异常值识别、聚类分析、SQL取数与销售数据解读等核心模块。资源以经典例题带动知识点讲解,例如Grubbs检验判断异常值、k-means聚类流程、按用户提取首个访问URL的SQL写法,以及针对周末销售偏低原因的运营改进思路,能帮助读者快速对照自身知识短板。包体为单份PDF文件,大小218KB,轻量易读,适合笔试前集中复习或日常查漏补缺。截至目前已有472人学习,可用于评估数据获取、业务理解和分析方法应用等综合能力,对正在准备数据挖掘或数据分析岗位笔试的读者有较高参考价值。

1. 从阿里数据分析师笔试题看岗位能力地图

这份数据分析笔试题集把阿里巴巴、腾讯、百度、网易、搜狐五家公司的真实笔试题目凑在一起,恰好拼出了数据分析岗完整的能力地图:统计学检验、聚类算法、SQL 取数、业务归因、试验设计、工程算法,六块一个不少。新入行的人别把它当成普通题库去背答案,建议按章节对能力缺口做自测:能否说清 Grubbs 检验的适用前提、能否用窗口函数改写取首个 URL 的 SQL、能否给销售数据的周末低谷做归因、能否把 AB 测试的抽样和检验步骤讲完整,这些才是真正的准入门槛。做了两三年数据分析的老手,反而值得回头重看第五题的事前试验设计——很多项目最后失败,不在模型精度,而在方案阶段的抽样和对照逻辑就已经错了。

2. 异常值识别进阶:Grubbs 检验与五种检测法的选型逻辑

2.1 异常值的统计定义与判别思路

异常值(Outlier)指样本中数值明显偏离所属样本其余观测值的个别点,数理统计里通常描述为“与平均值的偏差超过两倍标准差”。这个定义容易让人误以为 2σ 是通用硬阈值,实际它只是基于正态近似的经验速判。真实项目里,2σ 规则在样本量小、分布偏态时误判率很高:右侧长尾分布会把正常高值打成异常值,而重尾分布又会漏掉真正的离群点。所以笔试考 Grubbs 检验,本质是考你是否理解“假设分布 + 检验统计量 + 临界值”这套统计推断框架,而不是背一个阈值公式。

2.2 五种检验法的比较与适用场景

原题提到未知总体标准差 σ 时,五种检验法的优劣次序为 t 检验法、格拉布斯检验法、峰度检验法、狄克逊检验法、偏度检验法。这个次序反映的是检验功效与稳健性的权衡。实际应用中,我一般按下面这张表做选型:

检验方法核心思想适用场景主要局限
t 检验法(拉依达扩展)用 t 分布修正小样本临界值样本近似正态、单侧离群受均值/标准差污染,多重检验需校正
Grubbs 检验最大偏差与标准差之比构造 G 统计量单变量数据集、总体近似正态一次只能识别一个异常点,需迭代使用
狄克逊检验(Dixon)极差比构造 Q 统计量样本量小(n ≤ 30)对多个异常点同时存在时不敏感
偏度检验利用偏度方向捕捉单侧离群分布偏态明显的数据前提是分布形态已知
峰度检验利用峰度捕捉尾部极端值尾部较厚的连续数据对中等程度离群点功效较弱

从这张表能看出,Grubbs 检验的核心假设是“数据集来自正态总体”,它把异常值问题转化为一个假设检验问题:原假设是所有数据来自同一正态总体,备择假设是最大值或最小值是离群点。这比单纯画箱线图“肉眼找点”多了可量化的 P 值。但也要注意,Grubbs 检验每次只能揪出一个离群点,删掉后必须重新计算——因为残存的异常值会继续拉偏均值和标准差。

2.3 用 Python 实现 Grubbs 检验并联动可视化

Python 里没有直接叫grubbs的 SciPy 函数,但用 t 分布临界值可以手写完整流程。下面这段代码输入一个连续型一维数组,输出 G 统计量、临界值和判定结果:

import numpy as np from scipy import stats def grubbs_test(data, alpha=0.05): x = np.asarray(data, dtype=float) n = len(x) mean = np.mean(x) std = np.std(x, ddof=1) # 计算 G 统计量:|最大值或最小值 - 均值| / 标准差 G = np.max(np.abs(x - mean)) / std # 临界值由 t 分布修正得到,alpha 需除以 2n 做多重比较校正 t_crit = stats.t.ppf(1 - alpha / (2 * n), n - 2) G_crit = (n - 1) / np.sqrt(n) * np.sqrt( t_crit**2 / (n - 2 + t_crit**2) ) return G, G_crit, G > G_crit data = [3.2, 3.1, 3.4, 3.0, 9.8, 3.3, 2.9] G, G_crit, flag = grubbs_test(data) print(f"G={G:.3f}, G_crit={G_crit:.3f}, 异常={flag}")

这段代码有两个关键参数需要解释。第一,ddof=1表示用样本标准差而不是总体标准差,因为笔试场景里我们拿到的几乎都是样本,无偏估计更稳。第二,临界值公式里的alpha / (2 * n)是 Bonferroni 校正——对 n 个点做离群检测本质是多重比较,不校正会放大误报。实际使用时如果数据里存在多个异常点,应该每轮删除一个点后重新调用函数,直到没有异常为止,同时记录每轮删除的值,方便后面写数据质量报告。

配合可视化看更直观。用箱线图辅助预检是数据分析与可视化里的常见做法:先画seaboxplot看分布形状,如果箱子上下须之外的点不多,再用 Grubbs 做定量确认。箱线图用的是 IQR 规则(Q3 + 1.5×IQR),不依赖正态假设,和 Grubbs 检验正好互补——一个负责初步探查,一个负责给出可报告的 P 值。

2.4 异常值的处理决策:删除、替换还是保留

检出异常值只是第一步,真正影响分析结果的是后续处理策略。我的经验是分三种情况。第一,如果是数据录入错误(比如年龄字段出现 999,金额字段出现负数),直接删除或修正,并在数据质量报告里写明原因和比例。第二,如果是真实业务极端值(比如大促当天的销售额),不要急着删,先用 Grubbs 检验确认统计意义上的离群,再结合业务判断:这类点往往是高价值客户或真实峰值,删除会低估业务波动。第三,如果是建模场景,可以考虑用中位数或 Winsorize 缩尾替换,而不是直接剔除——树模型对异常值不敏感,但线性回归和聚类对异常点非常敏感,k-means 的均值更新会被极端点带偏。处理完后把原始值与处理后的值都留存,方便复盘时追溯。

3. k-means 到 K 中心点:聚类笔试题的计算过程与 Python 复现

3.1 聚类与分类的边界

聚类分析(Cluster Analysis)把研究对象划分为相对同质的群组,也叫分类分析或数值分类。笔试里最常见的考点是“聚类与分类的区别”——一句话概括:分类的类别标签是预先知道的,属于有监督学习;聚类的类别是数据自身结构决定的,属于无监督学习。很多候选人会答成“分类是按标签分、聚类是按特征分”,这个表述不够准确,关键差异在于划分前类别是否已知。聚类计算方法主要有五类:层次方法、划分方法、基于密度的方法、基于网格的方法、基于模型的方法。前两种基于距离度量,后三种分别针对不规则形状、高维网格、概率分布场景。

3.2 k-means 的手算推导与收敛判断

k-means 是划分方法里最常考的算法,原题要求描述计算原理和步骤。标准流程是四步:第一步,从 n 个对象里任意选 k 个作为初始聚类中心;第二步,把每个剩余对象按距离分配给最近的聚类中心;第三步,重新计算每个聚类的均值作为新中心;第四步,重复第二、三步直到标准测度函数收敛,一般用均方差(MSE)作为收敛判据。算法复杂度是 O(NKt),N 是数据量,K 是类别数,t 是迭代次数,实际场景 K 远小于 N,t 也远小于 N,所以它对大数据集相对可伸缩。

下面用一个 5 个二维点、K=2 的小例子手动推一遍,K=2,初始中心选 A1(1,1) 和 A3(8,8):

坐标到 C1(1,1) 距离到 C2(8,8) 距离第一轮分配第二轮分配
A1(1,1)0.09.9C1C1
A2(1,2)1.08.6C1C1
A3(8,8)9.90.0C2C2
A4(8,9)10.61.0C2C2
A5(9,8)10.61.0C2C2

第一轮结束后 C1 的均值是 (1.0, 1.5),C2 的均值是 (8.33, 8.33)。用新中心重新计算距离,A1、A2 仍然离 C1 近,A3、A4、A5 仍然离 C2 近,分配不再变化,算法收敛。这个例子也暴露了 k-means 的两个固有缺点:K 值必须事先给定,但非常难以选定;初始聚类中心的选择会直接影响最终结果,不同初始化可能得到不同的局部最优解。笔试如果继续追问,通常还会问“k-means 适合什么样的数据”——答案是适合密集的、类间区别明显的数据,此时平方误差最小;对环形、条状等非凸簇效果很差,这时应该考虑 DBSCAN。

3.3 用 scikit-learn 复现与 K 值选择

用 scikit-learn 复现上面的过程非常直接,但参数设置里有几个容易被忽略的细节:

import numpy as np from sklearn.cluster import KMeans from sklearn.preprocessing import StandardScaler X = np.array([[1, 1], [1, 2], [8, 8], [8, 9], [9, 8]]) # 先标准化再聚类:量纲不同会直接扭曲距离计算 X_scaled = StandardScaler().fit_transform(X) km = KMeans( n_clusters=2, init="k-means++", # 用概率方式初始化,避免随机中心导致的局部最优 n_init=10, # 跑 10 次选 inertia 最小的结果 max_iter=300, random_state=42 ) km.fit(X_scaled) print("标签:", km.labels_) print("聚类中心:", km.cluster_centers_) print("MSE:", km.inertia_)

这里init="k-means++"是关键参数,它的初始化策略是让初始中心彼此尽量远,能显著降低随机初始化带来的结果波动。n_init=10意味着算法独立跑 10 次,保留 SSE(簇内平方误差和)最小的一次,这是应对 k-means 对初始值敏感的标准做法。random_state固定随机种子,保证别人能复现你的结果。inertia就是我们手算过程中的“标准测度函数”,也就是各点到所属簇中心的距离平方和。

K 值选择没有银弹,但有两个可落地的辅助手段。一是肘部法(Elbow Method):对 K=1 到 10 分别跑 k-means,记录 inertia,画折线图,取“肘部”位置——inertia 下降速率明显变缓的拐点。二是轮廓系数(Silhouette Coefficient):计算每个样本与同簇样本的平均距离 a、与最近其他簇样本的平均距离 b,系数为 (b-a)/max(a,b),取值在 [-1,1],越接近 1 说明簇内紧凑、簇间分离;对不同 K 画轮廓系数均值曲线,取最高点。实际业务里还要结合可解释性,比如用户分群项目里 K=4 分出的四个群各自有清晰的画像标签,即使轮廓系数比 K=5 低一点,也值得选 K=4。

3.4 K 中心点算法与 k-means 的对比

网易笔试题考察了 K 中心点聚类(PAM),它和 k-means 的核心差异在于“中心”的定义。k-means 用簇内均值作为中心,K 中心点用簇内真正存在的某个样本作为中心(medoid),因此对异常值更稳健。PAM 的流程是:先为每个簇随意选择一个代表对象,把剩余对象按距离分配给最近的代表;然后反复用非代表对象尝试替换代表对象,判断替换能否改进聚类质量。判断标准里最经典的是四种情况——假设当前代表是 Oj,尝试用非代表对象 O 替换 Oj,考察任意非代表对象 p:第一种,p 当前属于 Oj,如果 Oj 被 O 替换后 p 离 Oi 最近,则 p 重新分配给 Oi;第二种,p 当前属于 Oj,替换后 p 离 O 最近,则 p 重新分配给 O;第三种,p 当前属于 Oi,替换后 p 离 Oi 仍然最近,则 p 分配不变;第四种,p 当前属于 Oi,替换后 p 离 O 最近,则 p 被重新分配给 O。四种情况下总代价下降,替换才被接受。

对比两者,k-means 计算快、适合大规模数据,但结果受异常值和初始中心影响大;K 中心点更稳健,但每次替换都要遍历所有非代表对象与所有代表对象组合,复杂度通常到 O(K(N-K)²),大数据集上跑不动。所以大数据分析与挖掘实践中,常见做法是先对数据做抽样或 Mini-Batch KMeans 粗聚类,再对异常敏感的关键群体用 K 中心点细化。另外还有一个容易忽略的细节:无论 k-means 还是 K 中心点,都必须先做标准化,否则量纲大的特征会主导距离计算,这在高维用户特征聚类里是新手最容易踩的坑。

4. SQL 取数与 B2C 销售归因:首个 URL 的三种写法

4.1 原答案的隐患在哪

原题要求从表 A(Member_ID、Log_time、URL)中提取每个用户访问的第一个 URL,形成新表 B,给出的答案是:

CREATE TABLE B AS SELECT Member_ID, min(Log_time), URL FROM A GROUP BY Member_ID;

这个写法表面看能跑通,实际存在语义问题:GROUP BY Member_ID后,SELECT 里的URL并不在分组键中,SQL 标准并不保证返回的是min(Log_time)对应那一行的 URL。某些数据库(比如 MySQL 的 ONLY_FULL_GROUP_BY 未开启时)会返回任意一行的值,Hive 早期版本也有类似行为,结果可能是用户第一条访问记录,也可能是最后一条,甚至是一个毫无规律的中间值。笔试现场写出这个答案,暴露出的是对分组聚合语义理解不深——只知道用 MIN 取最早时间,没意识到“和最早时间同行的其他字段”需要单独关联取回。

4.2 窗口函数改写与等价子查询

推荐优先用窗口函数,语义直接、可读性强,Hive、SparkSQL、MySQL 8.0 都支持:

CREATE TABLE B AS SELECT Member_ID, Log_time, URL FROM ( SELECT Member_ID, Log_time, URL, ROW_NUMBER() OVER ( PARTITION BY Member_ID ORDER BY Log_time ASC ) AS rn FROM A ) t WHERE rn = 1;

这段 SQL 的逻辑分三层。内层用ROW_NUMBER()按 Member_ID 分组(PARTITION BY),组内按 Log_time 升序编号,最早一条的 rn=1;外层用WHERE rn = 1过滤出每个用户的首条访问记录;最后CREATE TABLE B AS把结果物化为新表。ROW_NUMBER()的作用是给组内每一行生成不重复的序号,相比GROUP BYMIN()的写法,它的优势是能把“最早时间”和“最早时间对应的完整行”一次取出来,不用二次关联。如果数据库版本不支持窗口函数,退而求其次可以用等值关联的版本:

CREATE TABLE B AS SELECT a.Member_ID, a.Log_time, a.URL FROM A a JOIN ( SELECT Member_ID, MIN(Log_time) AS first_time FROM A GROUP BY Member_ID ) t ON a.Member_ID = t.Member_ID AND a.Log_time = t.first_time;

子查询先计算每个用户的最早时间,再与原表按用户和时间做等值连接。这个写法的问题在于:如果同一个用户在同一个时间戳有多条访问记录,连接后会产生重复行,需要再套一层 DISTINCT 或 ROW_NUMBER 去重。所以在生产环境里,我会优先使用窗口函数版本,只有在必须兼容 MySQL 5.7 以下的老系统时才用子查询关联。还有一点容易被忽略:Log_time字段如果是字符串类型的日期(比如'2024-05-20 10:30'),直接 ORDER BY 是按字典序排的,格式不统一时会出错,建议先CAST(Log_time AS TIMESTAMP)或统一格式再排序。

4.3 从 SQL 取数到销售数据归因分析

SQL 是取数基本功,但笔试第四题明确告诉你:光会取数不够,数据解读能力才是区分度所在。原题给的是某 B2C 电子商务网站一周销售数据,用户群是办公室女性,销售额集中在 5 类产品上。假设一周数据如下:

星期销售额(万元)
周一12.8
周二13.5
周三12.1
周四13.2
周五11.6
周六6.4
周日5.8

从数据能直观看到的结论是:周末销售额明显偏低。但归因不能停在“周末没人买”,要拆成两个视角。消费者视角:办公室女性是核心用户群,周一到周五的购买场景通常与工作间隙、午休浏览相关,周末脱离办公场景后触达减少,购买欲望下降。产品视角:这 5 类产品本身是否具备周末消费属性?如果品类里没有适合周末场景的商品(比如零食补货、居家用品),那么周末流量即使来了也转化不了。运营改进计划也对应分两条线:一是引导提醒,通过邮件、短信、App Push 在周五下午或周六上午推送“周末备货”主题,把购买场景从办公室迁移到家庭;二是促销拉动,周末针对 5 类主打产品做限时折扣或满减,人为制造关注点。

这里还有一个电商业务数据分析中容易犯的错误:拿到一周数据就直接归因,没有先剥离周期性。正确做法是先看这个周有没有节假日、有没有大促活动日、上周同期数据如何。比如如果周一本身是 618 大促后的回落日,销售额低就不是“周一效应”而是“大促透支效应”。更严谨的方案是至少取 4~8 周数据,按星期几做同环比,再用异常值检测把促销日标记出来,最后才做归因。数据解读的价值不在于描述“周末低”这个现象,而在于区分哪些是可干预因素(促销、提醒、选品),哪些是结构性因素(目标用户的消费习惯),运营动作只对可干预因素有效。

5. 事前试验与 AB 测试:分层抽样和两独立样本 t 检验的完整落法

5.1 试验方案要回答什么问题

第五题的场景是:公司针对 A、B、C 三类客户提出统一改进计划,目标是提升客户周消费次数,要制定事前试验方案来支持决策。第一问“试验需要为决策提供什么样的信息”,很多人的回答是“测试有没有效果”,这不严谨。正确的拆解是:试验要能证明该改进计划对 A、B、C 三类客户的周消费次数有“统计显著”的提升——不仅要说有效果,还要排除随机波动造成误判的可能。同时还要回答效果量的大小:提升了 0.5 次和 0.05 次,对业务决策的意义完全不同。所以事前试验方案需要包含三个要素:抽样方法、采集的数据指标、统计检验方法,三者缺一不可。

5.2 分层比例抽样的计算

抽样方法选分层比例抽样是合理的,因为 A、B、C 三类客户在总体中的占比不同,简单随机抽样可能让样本中某类客户数量过少,导致该类客户的检验功效不足。分层比例抽样的做法是先按客户类别分成三层,每层按其在总体中的比例分配样本量:

# 假设总体中三类客户数量 pop = {"A": 10000, "B": 15000, "C": 25000} total = sum(pop.values()) # 50000 sample_size_total = 5000 # 预定总样本量 allocated = { k: int(round(sample_size_total * v / total)) for k, v in pop.items() } print(allocated) # {'A': 1000, 'B': 1500, 'C': 2500}

这里sample_size_total * v / total就是按每类客户占比分配样本,A 类占 20% 就抽 1000 人,C 类占 50% 抽 2500 人,保证各类客户的样本结构与总体一致。需要采集的数据指标有两类:客户类别用于分层标识,前后周消费次数用于检验效果;改进前的周消费次数作为基线,改进后的周消费次数作为度量。注意要把两次数据都采全,有缺失值的样本要提前剔除,否则会出现“只采到改进前数据但客户流失”的不完整配对,影响检验有效性。

5.3 两独立样本 t 检验的前提与计算

题目给出的统计方法是针对 A、B、C 三类客户分别做改进前后周消费次数的两独立样本 t 检验。用 Python 实现,核心是scipy.stats.ttest_ind

from scipy import stats # 假设改进前抽样 120 人的周消费次数 before = [2.8, 3.1, 2.9, 3.0, 2.7, 3.2, 2.6, 3.3] # 示例数据 # 假设改进计划落地后独立抽样的 120 人周消费次数 after = [3.4, 3.6, 3.1, 3.8, 3.5, 3.2, 4.0, 3.7] t_stat, p_value = stats.ttest_ind(after, before, equal_var=True) print(f"t={t_stat:.3f}, p={p_value:.4f}") if p_value < 0.05: print("差异显著,改进计划有效") else: print("差异不显著,无法判断有效")

ttest_ind的两个关键参数是:equal_var=True对应经典的学生 t 检验,假设两组方差齐性;如果两组标准差差异较大,应设equal_var=False使用 Welch 修正,这是更稳健的做法,即使方差不齐也能用。两个样本是独立抽的,即改进前样本与改进后样本来自不同客户,而不是同一批客户——如果是同一批人测量两次,那就应该用ttest_rel配对 t 检验,功效更高。题目问的是“两独立样本 t 检验”,按独立分组设计即可,但实际业务中如果条件允许,优先用同一批客户的前后对比,这样能剔除个体差异,同样的样本量更容易得到显著结果。

5.4 样本量估计与常见坑

事前试验最容易翻车的是样本量不够,跑完两周发现 P 值在 0.05 到 0.10 之间,不上不下。样本量大小取决于四个输入:显著性水平 α(通常 0.05)、检验功效 1-β(通常 0.80)、两组均值差 δ、总体标准差 σ。两独立样本均值检验的样本量公式是 n = 2σ²(z_{α/2} + z_β)² / δ²,每组需要的样本量:

from scipy import stats alpha = 0.05 beta = 0.20 z_alpha2 = stats.norm.ppf(1 - alpha / 2) z_beta = stats.norm.ppf(1 - beta) sigma = 2.0 # 周消费次数的标准差,从历史数据估计 delta = 0.5 # 希望检出的最小效果:提升 0.5 次/周 n = int(2 * sigma**2 * (z_alpha2 + z_beta)**2 / delta**2) + 1 print(f"每组至少需要 {n} 人")

这里 σ 用历史数据算,比如过去一个月客户周消费次数的样本标准差。z 值来自标准正态分布分位数,stats.norm.ppf(0.975)约为 1.96,stats.norm.ppf(0.80)约为 0.84。把公式跑出来后,如果每组需要 251 人,而分层抽样每层只分到 200 人,就要调整总样本量或降低预期效果 δ——这是方案评审阶段应该完成的容量计算,而不是试验结束后再解释。

试验设计还有三个常见坑。第一,随机化单元选错:如果改进计划是针对客服服务的,同一客服服务的客户不满足独立性,应该按客服分组而不是按客户随机分组。第二,AA 测试缺失:上线正式实验前,先跑一段没有真实差别的 AA 测试,验证两组基线指标一致,避免分组偏差导致误判。第三,多重比较问题:A、B、C 三类客户分别做检验,做了 3 次 t 检验,整体犯第一类错误的概率会大于 0.05,可用 Bonferroni 校正把 α 调整为 0.05/3 ≈ 0.0167。这个细节如果能在笔试或面试里主动提出来,通常能明显加分。

6. 编程与算法笔试通用解法:归并排序、哈希冲突与 FMM 分词实现

百度、网易、腾讯的笔试把范围从统计拓展到工程算法,其中三个考点最具代表性:排序算法的稳定性、哈希冲突的解决方案、中文分词的前向最大匹配算法。

先看排序稳定性。快速排序不稳定,是因为它基于交换,相等元素的相对次序在分区时可能被打乱;归并排序稳定,是因为合并两个有序序列时,遇到相等元素先取左半部分的元素。笔试若让你手写归并排序,用链表实现能同时考察指针操作:

struct Node { int v; Node *next; Node(int x) : v(x), next(nullptr) {} }; Node* merge(Node* a, Node* b) { Node dummy(0), *cur = &dummy; while (a && b) { if (a->v <= b->v) { cur->next = a; a = a->next; } else { cur->next = b; b = b->next; } cur = cur->next; } cur->next = a ? a : b; return dummy.next; }

哈希冲突的解法里,笔试常要求写两种并比较优劣,最基础且实用的方案是链地址法:每个桶挂一条链表,冲突元素追加到链表尾部,优点是删除操作方便、扩容简单;另一种是开放定址法,冲突时按线性探测或二次探测找下一个空位,优点是空间连续、缓存命中高,但删除操作复杂且表快满时性能急剧退化。至于“10 亿 URL、平均 20 字节、8G 内存统计频次”这类题,思路固定:先按 URL 做哈希分片到多个小文件,让每个文件能在内存中建 HashMap 统计频次,再用大小为 K 的小顶堆取 TopK,对应每行一个 URL 去重的场景。

最后是 FMM 分词,网易和百度都考过。前向最大匹配的核心思路并不复杂:从句子当前位置开始,取最长为 max_len 的子串查词典,命中就切分并前移,不命中就缩短窗口继续查,直到单字兜底。关键在词典的struct dictnote设计,用 Trie 树比哈希表更合适,因为匹配过程本身就是逐字下探的:

struct DictNode { unordered_map<wchar_t, DictNode*> children; bool is_end; string word; // 命中时的完整词 };

匹配时从根节点出发,沿句子的字序列在children中逐层查找;is_end标记当前位置是否为完整词。接口设计上,题目建议用int FMM(vector<wchar_t> sentence, DictNode* root, vector<pair<int,int>>* results)这类输出位置对的签名,比直接返回字符串更灵活——下游不管是做词性标注还是品牌检索,拿到位置索引都能自由切分。扩展“查找包含手机品牌的网页”时,只需把品牌词表(如 iPhone、诺基亚)也插入同一棵 Trie,匹配到品牌词时额外标记一个品牌 ID,再从网页文本里扫描品牌词出现的所有位置,即可实现泛化的品牌发现。FMM 的短板是切分歧义:正向最大匹配对“南京市长江大桥”这类歧义句容易切错,改进方向是引入逆向最大匹配(RMM)并比较两种结果的分词数量,取更少的一种——这就是双向最大匹配的雏形,也是笔试后续追问时值得展开的技术点。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/19 13:24:11

Claude Code 月耗 1199 美元的 token 账单,TaoToken 能看清哪几笔

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/19 13:23:43

历史观看数据驱动营销:从用户分群到会员转化的实战指南

做营销这几年&#xff0c;我越来越觉得&#xff0c;手里没点真实行为数据&#xff0c;光靠拍脑袋定方向&#xff0c;翻车概率太高了。今天想聊的是我们团队在“7v7.7cc”这个内容平台上完整跑过的一个方向&#xff1a;把历史观看数据当成营销策略的底层燃料&#xff0c;从用户分…

作者头像 李华
网站建设 2026/9/19 13:22:28

N_m3u8DL-RE 免费流媒体下载工具:10 分钟跑通 m3u8 与 DASH 下载

N_m3u8DL-RE 免费流媒体下载工具&#xff1a;10 分钟跑通 m3u8 与 DASH 下载 【免费下载链接】N_m3u8DL-RE Cross-Platform, modern and powerful stream downloader for MPD/M3U8/ISM. English/简体中文/繁體中文. 项目地址: https://gitcode.com/GitHub_Trending/nm3/N_m3…

作者头像 李华