“阿里灵杰”问天引擎电商搜索算法大赛 | 学习笔记

简介: 快速学习“阿里灵杰”问天引擎电商搜索算法大赛

开发者学堂课程【第八届大学生创新创业大赛阿里命题“阿里灵杰”问天引擎电商搜索算法大赛培训“阿里灵杰”问天引擎电商搜索算法大赛学习笔记,与课程紧密连接,让用户快速学习知识。

课程地址https://developer.aliyun.com/learning/course/1043/detail/15200


“阿里灵杰”问天引擎电商搜索算法大赛

 

内容介绍:

一、比赛介绍

二、比赛内容

三、比赛数据

四、结果提交

围绕着阿里天池问天引擎电商搜索算法赛进行讲解,讲解过程中,主要内容围绕着比赛开始,也会讲解一些具体的上分点和解题过程。

 

一、比赛介绍

受疫情催化影响,近一年内全球电商及在线零售行业进入高速发展期。作为线上交易场景的重要购买入口,搜索行为背后是强烈的购买意愿,电商搜索质量的高低将直接决定最终的成交结果,因此在 AI 时代,如何通过构建智能搜索能力提升线上 GMV 转化成为了众多电商开发者的重要研究课题。

也就是说,这个课题关键点在于在搜索场景下面去做业务背景,因为文本其实它很多一些场景下面,业务场景不同,数据是不一样的。

 

二、比赛内容

本次题目围绕电商领域搜索算法,开发者们可以通过基于阿里巴巴集团自研的高性能分布式搜索引擎问天引擎(提供高工程性能的电商智能搜索平台),这个引擎可以先不管,可以理解为类似于 face 的向量检索工具,但在做比赛的时候不需要关注,因为评测它使用引擎去做,我们提交的不是引擎,提交的是向量。比赛内容就是,数据来自于淘宝搜索真实的业务场景,整个搜索的商品按照类别进行随机采样,保证了类别的多样性,这是它的数据集说明。它的数据集来自于淘宝搜索,也就是淘宝首页的搜索或者淘宝 APP 的搜索场景。它的标签怎么得到的?搜索 query 和相关的商品来自点击日志,并通过人工的确认完成了校验,所以搜索词叫 query,检索得到的商品就是相关商品,这是重要的比赛背景以及它的业务场景。

比赛分为初赛和复赛两部分。初赛部分,可以在线下进行构建召回模型,拿到的是100万全量 Doc,以及10万条 query 做训练集,然后需要构建召回模型。每次提交的内容为100万的文本的 embedding,以及测试级文本的 embedding,也就是并不是直接找到结果,相当于提交两个矩阵,这两个矩阵再去在天池搜索引擎上面,它的问天引擎上面进行检索,打分就是去提交 embedding 的两个矩阵,它在进行检索得到评价指标。它的检索本质上也是用类级或者用 MSE 做距离计算,也可以在本地模拟,初赛是这样的规则,就是可以在本地进行,当然它也提供运行环境,这个不影响。在复赛时候,复赛的应用场景就是在进入复赛之后,需要在阿里 pad 平台上面进行训练模型,不能在本地进行了,需要在线上进行。在复赛的时候,它要求更多,相当于直接将模型在线上进行训练,而且复赛限制了深度学习框架,复赛只让使用 TensorFlow1.12 版本。所以初赛和复赛任务流程上面是不同的。为什么现在还是 TensorFlow1.12?在很多大公司里面,现在仍然是在使用 TensorFlow1。

 

三、比赛数据image.png

整体数据集是这几个文件,在比赛官网上面也写了。这个corpus 不会 TensorFlow,不会 TensorFlow 可以先学,先保证初赛成绩比较好,其实有很多 TensorFlow 的相关模型,还是一点几版本,应该难不倒大家。先看数据集,数据集其实就是这四个文件,在比赛官网上面有写的这几个文件,image.pngcorpus、train.query 以及 qrels,这个地方相当于 query 和训练集的标注。Data_check 是检查提交结果的文件,dev.query 是测试集的文本。

这几个文件主要是这四个文件,第一个 corpus,相当于 document,我们的文档库,这个文档库有一些关键点,这个 title 相当于商品 product title,一般情况下,淘宝相当于是商品的一个 title,它的文本长度在30个字符左右,这个 corpus 相当于大概100万条文本。train.query.txt 相当于训练集,dev.query.txt 相当于测试集,测试集是1000条,训练集是10万条。训练集和 corpus 怎进行对应上?通过 qrels.train.tsv,平均长度好像是31左右,它是 query 和 document 进行对应。train.query.txt 的 query 来自于训练集的 query,dev.query.txt 的 query 来自于测试集的 query,qrels.train.tsv 的 document 对应于具体的 corpus 的文件夹里面,所以整体数据集的对应关系是这样的,所以第一列是 query,第二列是 document。再来看看它的文本类型,区别是非常明显的,“美赞臣亲舒一段”相当于是一个 keyword,这个 keyword 其实是用户在输入的具体的带检索的文本。“電力貓”其实是个短文本,但需要跟长文本进行匹配,所以我们的任务并不是一个常规文本的匹配任务,可能是文本检索或者这种非的称的文本检索任务,所以首先要把数据集弄清楚。

数据集的整体形式、文本行,可以从官网或者网页上找到,就不做过多介绍。

 

四、结果提交

初赛提交要求,通过短文本检索得到对应的长文本,来看怎么一步一步进行解决。

首先,看具体的评价指标。评价指标本质上是检索的 order,rank_i 代表了测试集的 query 对应的 doc 在检索结果返回的位置,也就是它的次序,如果它排在越前面,得到的得分就越靠近1,如果它排在越后面,它的得分就越低。image.png

它直接相当于是以排序结果它的 order 的导数,进行评分就行了。

初赛的提交方式,不是直接提交文本,数据集的提交形式它不需要提交对应关系,它需要提交 embedding 的矩阵,也就是需要对 corpus,也就是 doc 进行嵌入,以及 query 进行嵌入,需要将具体的文本把它转变成两个矩阵,写到文件里面,再进行打包提交。有个关键点在于所有的 query 需要将它编码到128维,以及 document 也是需要将它编码到128维,128维是赛题规定的。常见的一些 bert 模型,它其实输出的维度就不是128维,所以如果直接用 bert 模型,可能在这个地方就不能直接用。

解决这个赛题任务有很多种解决方法,可以把它当做文本匹配来做,但是,如果将它当做文本匹配来做,最终提交的不是匹配关系,需要将 query 和 Document 同时编码到向量空间内,所以它的任务应该是非对称的文本检索任务。非对称的文本检索就是 query 其实是一个短文本,但是待匹配的文本是一个长文本,在比赛里面,它的一些数据有可能有一些是 hard example,就是文本之间有可能没有重合单词。一个 query 对应于 document 应该是一一对应的,具体的 query 和 document 它们之间有可能文本之间没有重合的。

具体的赛题可以去做一些仔细的分析,比如文本长度的分析,以及关键词进行分析,以及 hard example 或者 easy example 的分析,都可以去进行分析,这个分析对后续的建模都是有帮助的。解决赛题的思路有三种,第一个是直接使用关键词进行匹配,识别出 query 和 corpus 中间的关键词,使用关键词的向量进行编码;第二个思路,可以使用 sentence-bert 结合比赛的标注数据进行训练;第三个思路,用 simcse 进行无监督对比学习进行训练,这三种方法都是可以进行尝试的。先看第一种思路,读取数据集,代码在最下面,最终的代码都放在文件夹上面,点击进去就有个 get up,可以找到网页 datawhalechina-competition-baseline。image.png

读取数据,直接使用 pd.read_csv 把它读取进来行了,都是使用 table 之间进行分隔的,设置 sep 读取就行了。接下来可以设置 index,优点在于接下来的索引就直接使用  query 或者 query 的编号以及 document 的编号进行索引就行了,这是 set_index,不用绝对的位置,直接使用具体的 query 取值来进行索引,这是比较方便的。

接下来看看训练数据以及它对应的 query 以及它检索得到的,或者它真实的标签,image.png

左边是 query,右边是真实的 title,query 这个地方“美赞臣亲舒一段”,title 其实也有“美赞臣”的。再来看“草莓盆专用夹”,title 里面也有“草莓”,但是 title 里面没有“专用夹”。再来看“塞塞乐”,这个 query 在 title 里面也是没有出现的。也就是具体的数据集其实可以分为两类,一类可以通过 keyword 能够找到 document,也就是它们之间共用一些部分的一些单词,但有些是没有共用的,比如很典型的“塞塞乐  婴儿童玩具6个月以上8宝宝益智早教0-1岁男孩女孩六9月+7新生礼”,通过关键词是找不到带检索的结果的,只能从语义的角度进行建模。image.png

将原始的数据集打印,就是原始的 query,以及对应的 document 的 title。

接下来首先进行分词,因为想用词向量做检索,直接用 jieba 来做,可以用其他的,但是建议自己去构建一些词典,比如一些品牌,image.png

这个 jieba 它有些品牌分的不是特别准,可以通过 jieba 增加分词的性能。如何找到词典或品牌?多去看看分词结果,需要做新词发现,但如果人工筛一遍其实也费不了多少事。image.png

接下来对训练集就是的 document title 以及训练集的 query,以及测试集的 query,都对它进行分词,分完词之后,它都是 List 类型的。image.png

对所有的文本,将它训练词向量,直接将它的单词设置维度为128维,也就是将所有的单词转变为128维的向量。为什么是128维?因为提交的结果就是这个维度。训练过程直接使用 GCM 的 word2vec 进行训练,有没有必要直接用已有的词向量,比如像腾讯的词向量,或者其他的一些词向量?个人觉得没有必要,因为数据集是足够大的,也可以尝试用已有的一些词向量,也可以对比一下它的效果。image.png

通过词向量进行训练对比得到的,输入一个“小天鹅”,或者输入一个电冰箱的名字,或者空调的名字,其实可以检索得到,或者可以计算得到跟它相似的单词,表明这个词向量是有效的。image.png

可以将原始的文本转变成 ID 类型。这一步将所有的文本原始的是从单词都把它转成 ID 类型,

model.wv.key_to_index[“女”]

word vector 它会维护 word 到 index 的关系,提前将所有的文本都把它转变成单词之后,文本比如“我 爱 阿水”,它会转变成“10 230 89”,它会用数字来代替,在 RP 建模里面是非常常见的一种操作,就是把它转变成 ID,转变成 ID 有什么作用?训练得到词向量之后,这个词向量可以直接进行使用的,直接 model.wv,输入比如“格力”,可以直接进行使用,

model.wv[‘格力’]

但是如果直接转变成 ID 之后,数字其实也是可以的,

model.wv[123]

直接输入 index 其实也是可行的,而且使用 index 可能会更加方便,也可以直接输入多个,它返回的是一个 shape,就是2乘128,

model.wv[[123,234]].shape

假如试验一下多个,它也是可行的,

model.wv[[123,’填’]].shape

可以转变成 ID,也可以不转。image.png

接下来可以做 IDF 的计算,并不是所有的单词都是相同重要的,这个地方的 IDF 是 TFIDF 里面的 IDF,它计算单词的重要性,我们的句子里面,比如“我 爱 阿水”里面,“我”和“爱”两个字,它出现的频率肯定比较高,在这个句子里面,“阿水”的 IDF 应该是最高的。这个地方的 IDF 用来做识别出 query 和 doc 里面哪些词是重要的,这个地方的 IDF 直接使用 TfidfVector 计算得到,并没有使用有监督的机器学习。计算得到 IDF 之后可以做一个操作, image.png

把所有 IDF 小于10的这些单词把它筛选出来,为什么是10?设置为10的情况下,它能够将一些常见的单词过滤掉,可以理解为是人工设置的 CS。得到了不重要的单词之后,接下来可以使用一些具体的编码,怎么编码?就是无监督的编码,直接将 sentence 再结合 word vector 做编码,对于 sentence,它有多个 word,已经将它进行分词,分完词之后直接做判断,做判断不要在常见的单词里面出现的一些单词,把它筛选出来之后,再使用它进行获取它的词向量,image.png

这个地方的词向量就是一个句子的词向量,是N乘以128维的维度,是一个矩阵,N是它筛选之后剩下来的多少个单词,将句子的词向量把它转变成单词的词向量,直接把它进行 pooling,或者求一个 max pooling,或者求一个 min pooling,这样返回得到的就是一个句子的词向量,这个句子的词向量就是128维的。整体的思路简单,但是它能够有3.5%的得分,整体的流程就是这样的。接下来的过程,就是对 corpus 进行编码,对 train 进行编码,以及对 text 进行编码。image.png

整体的过程,这一步可能需要编码,可能需要花费40分钟,因为 corpus 就是这种 document,总共是100万条,它编码的时间也是比较长的。编码完成之后,如果想要在本地做检索,可以参考直接在本地做规划,把它进行求类集,就可以做编码,image.png

这个可以在本地构建验证集,可以验证结果的有效性,image.png

如果不想验证,可以直接将它的结果写到 swing 里面,是可以直接提交的。这个代码没有用 GPU 的,就是12核的机器。如果大家自己下去跑,应该也是在一个小时之内可以跑完整个过程,提交上去是0.035左右,没有使用到标签的信息,完全是无监督的。

这个地方是全部把它拼接到一起训练,所以不会出现未登录词的情况。

提交的是这两个文件,query embedding 和 doc embedding,这两个文件相当于是矩阵的内容,提交上去应该是在0.035左右的成绩。最上面的代码是读取文件,image.png

可以用 bert,没有用到标注信息。

Word vector 怎么看训练好不好,可以看它的相似单词。

最后提交结果如何利用,提交的 embedding 是在天池的环境上面进行检索,所以并不需要做额外的操作,提交的是 embedding 两个矩阵。

是编码天池替我们判断编码的结果?是这样。

Word vector 训练的输入输出分别是什么?Word vector 是无监督的训练,它没有使用到标注,Word vector 应该有两种训练方法,相当于中间的单词预测两边或者两边的单词预测中间,可以去看看它的训练过程,可以直接用 GCM。

线上得分怎么算的?提交的 test 或者 dev 1K乘以128的矩阵,还提交 corpus 的,也就是 document 的结果,是100万乘以128维的矩阵,在进行计算的时候,就是 dev 的测试集的向量,128维的向量,从 document 里面,这100万里面去找到跟它能成功匹配的结果,比如它的检索结果是95,96,93,157,1009,这个地方检索得到的是在 document 里面的次序,跟它最相近的一些单词的次序,会有计算应该是 MRR,如果在第三个位置检索得到的是正确结果,那么它的得分就是1/3,这个计算相似度的过程,在阿里内部应该是使用内积进行计算的。

官方是不是没给相似度函数?官方应该是内积。他们好像是欧式距离,欧式距离其实也行,因为我自己做了一个测试,线下去跑了一个无监督的方法 unsuperised,线下用10万条去检索它的精度是0.038左右,提交上去也是接近于这个分数的,0.038是本地的分数,0.035是线上的分数,两者是比较接近的。

双卡是不是可以用欧式距离当损失函数?可以,就是对比损失。使用 sentence burts 是能训练的,但效果不能保证,因为我还没有训练完成。首先,读取数据的代码,image.png

然后分词。

线下怎么得到分数?不是没有测试数据吗?有测试数据的,image.png

这个地方是直接使用训练集标注进行评价的,训练集是给了的,这是10万条的标注信息是直接给的。

怎么在本地跑分数?直接使用 train 在 corpus 里面进行检索,有了标注信息之后,算它的 MR,可以用10万条里面9万条做训练,1万条当测试集,没直接用训练集当测试集,本质上是这样的。

接下来仍然先做分词,也算一算 IDF。sentence bert 本质上,可以打开 sentence bert 它的官网,这个库其实是很好用的,训练代码基本上是参考它写的,image.png

训练代码是将 query 和 document 都输入到 sentence bert 里面。

看看它的思维导图,image.png

Sentence bert 它的计算就是对于两个文本都通过 bert 进行编码,将两者通过全限阶层把它编码到相同的维度,然后使用内积距离做它的损失函数,这就是 sentence bert 的原理。Sentence bert 的损失函数可以进行修改,这是它的原始模型。

接下来需要构建一些副样本,qrels.train.tsv 是正样本,在训练 sentence bert 的时候其实是需要副样本的,所以需要去采样副样本,数据集有 query 和 document 对应的关系,这个标签是唯一的,还要找到它们不对应的情况,它们标签为0的一些情况,所以需要做采样得到一些副样本。采样负样本也有一定的操作,我做的一些尝试本质上是使用相同单词,然后去找到负样本。“美赞臣亲舒一段”是 query,在找负样本的时候是找包含相同单词,但不是非匹配的关系,“美赞臣亲舒一段”与“有现货美国美赞臣 Enfamil 婴幼儿宝宝多维综合维生素滴剂含铁50ML”这两个是不匹配的,这个样本是在 corpus 里面包含“美赞臣”这个单词的,相当于是直接可以通过构建 control vector,通过 IDF 可以筛选得到关键词,然后通过关键词可以构建一个 count vector,就可以找到包含相同 count vector 的这些文本,也就是负样本。

正负样本的比例是怎么样的?不均衡怎么办?可以自己控制采样的比例,因为现在这个模型还没有训练完成,所以我也不好说它大体是什么比例。

有点像对比学习的感觉?对,这个其实就是对比学习,看一下这个,image.png

Sentence bert 其实它本身就可以用来做对比学习,它是一种有监督的。

Negative sample,度量学习、检索,其实跟一个推荐系统是有点类似的,广告推荐系统里面分为召回、排序,一个模型如果是想要把它做的更加精细,先做一个召回,然后再做一个排序。召回可以使用 key word 去做,然后再使用排序,排序可以使用 point ones 的一些排序的样本,就是使用 sentence bert 这种排序模型来做,key word 本质上是做召回的,但是这个地方是直接使用 key word 把它构建的负样本。image.png

所以这个地方如果想要构建负样本,本质上也很简单,通过key word 找到包含了相同单词的,但是不是正样本的这些样本就叫负样本。image.png

把它分为两类样本,负样本可以有两部分,一个是 hard example,一类是 easy example。两者有什么区别?这个地方仍然是在实验过程中,并没有保证它一定有效,hard example 包含了相同关键词的,但不是正样本的这种情况,easy example 就是随机采样。

正、负样本的比例有什么设置说法?正负样本的比例暂时是在1 : 20左右。

如果构建了训练样本之后,就有一个正样本和一个负样本,然后就可以构建验证集以及训练集 hard example 以及 easy example。训练集和验证集构建的过程跟之前的是一样的,image.png

把构建得到的样本转变为 inputexample,转变完成之后就可以构建验证集,image.png

验证集就是使用原始的标注,挑选其中的1000条做验证集,验证集也是需要构建正负样本的,构建得到数据集之后就是训练,训练是使用 sentence bert 来做的,Sentence bert使用起来稍微比较方便,也可以自己来搭建模型,image.png

可以设置它的 out_feature,所有的文本可以把它编码到128维。然后使用 bert-base-chinese的 Base model 搭建 sentence。Max_seq_length 设置的是50,可以做修改。image.png

Losses function 设置的是类几距离,cosine 的相似度,应该是可以选择其他的,得到了数据集以及模型之后,接下来训练就行了。

这样负样本不会太多吗?可以尝试改这个比例,最开始设置的是1 : 20,losses 应该是可以选其他的,也有 MSE losses,如果想要用 MSE losses 算也是可行的。image.png

这个训练也是很简单,直接设置的训练的 epochs,evaluator 以及它的保存,训练完成之后也可以按照之前的思路做验证。

复赛用 TensorFlow 怎么办?先把流程走通,如果想要再去用 TensorFlow。

分类负样本的比例太多了。这个地方采样的是20个作为的负样本,模型并没有训练的很好,看一下训练的日志,image.png

这是它的验证集,Cosine 的系数不是特别高,最高是在0.84,效果并不是特别好。

如果想要继续,可以沿着三个思路继续。也可以使用 Simcse,就是无监督的对比学习,使用 dropout 作为构建的负样本来做尝试也是可行的。

什么是 hard example 和 easy example?我是自定义的,如果 query 和 title 之间有单词重合,就认为它是 hard example,如果它们之间没有单词重合,就认为它是 easy example。

Simcse 在做?是可以的,这是很靠谱的无监督的对比学习方法。

词向量不需要预训练?这是直接用比赛的数据集训练的词向量的,并没有使用其他的。

Simcse 有资料推荐吗?在 get up 上面有很多。

DSSM 可以吗?可以的,但是估计它的效果没有 simcse 好。

128维在 sentence bert 里面怎么进行处理的?去看它的代码,直接搜索,使用 sentence transform 库,在它的 model里面有,都是开源的。

是用比赛的 doc 训练词向量吗?是这样做的。

Bert 训练词向量,可以跟任务进行训练吗?可以的,就是在做 fighting 的时候。

Bert 词向量之间的差异性怎么解决?不太清楚,因为我暂时也没做这么深入。

大概要跑多久?如果是使用 sentence bert,可能需要好几个小时。

前几是0.2几,感觉跟欧姆的方向有很大不同?无监督精度肯定会比较差一点。

比赛可以使用外部数据集吗,比如词库?不太清楚。

Baseline 在哪可以获取?Baseline 在网页里面。

Simcse 已经训练了17个小时,有监督还可以尝试哪些方法?在 Sentence bert 里面有一个库有讲到一些知识点,image.png

它是一个非对称的检索,可以看一下 MS MARCO 数据集其他的一些模型,这个学术任务跟比赛的任务是非常相似的。

有监督的 simcse 就0.2多了?对,可以参考 simcse 的训练。

Simcse 可以用有监督吗?可以用有监督,simcse 可以用有监督进行训练。

在数据处理这一步还需要有什么方法?如果想要处理,key word 在线下做一些构建数据集,也就是构建 hard example和 easy example 是有用的,key word 可以做筛选,可以构建自定义的词典,就是 jieba 里面的自定义的词典。

IDF 代码能稍微讲一下吗?IDF 本质上就是单词在所有文档里面出现的频率的导数,可以直接手写,也可以直接使用 SK 里面的调用。

Simcse 有监督效果好还是无监督效果好?肯定是有监督的,key word 可以自己构建,主要是在线下做数据集的时候会有用到,线上因为提交的都是矩阵的,所以 key word 已经作用不大了。

无监督可以把所有的数据集都训练?可以的,可以先做无监督再做有监督。

SE 效果不一定变好?任务它是一个实体识别,其实本质上在做的任务它不是一个类别分类,检索得到的相当于是一个query 检索得到一个 product,关键点在于 product 的正负样本怎么构建,simcse 可能是比较有效的,因为它通过dropout 构建负样本是比较有效的,当然也可以尝试其他的方法。

有好的算力平台推荐吗?可以使用 PaddlePaddle,就是在 aistudio 上面,aistudio 是可以支持跑 GPU 的,虽然它是非使用 PaddlePaddle 的,它的环境是免费有 GPU 的。

cse 应该和 sentence bert 差不多?不一样,先看一下 aistudio,启动之后,它可以选择环境,有免费的 GPU 的。Simcse 就是同一个样本都通过网络模型,然后得到两个 feature,由于网络模型是加了 dropout 的,同时对同一个样本进行正向传播两次,它得到了两个特征不一样,还有另一个样本,另一个样本就是一个负样本,feat 是锚点,feat' 是正样本,feat" 是负样本,它可以使用无监督进行训练的,使用 dropout 进行构建正负样本的。

Dropout 是无监督构建正样本?是的。

这个比赛大家也可以尝试做一些数据扩增,比如随机的删除,对标题进行删除,随机对一些文本进行替换,也可以构建正负样本。

有什么数据增强的思路?可以做随机的单词插入,其实它就是对于 title 而言,可以添加一些关键词。

有监督的 sentence bert 怎么构建负样本?参考刚才构建sentence bert 负样本的过程。

相关实践学习
基于阿里云DeepGPU实例,用AI画唯美国风少女
本实验基于阿里云DeepGPU实例,使用aiacctorch加速stable-diffusion-webui,用AI画唯美国风少女,可提升性能至高至原性能的2.6倍。
相关文章
|
9天前
|
索引
浅谈两个重要的搜索算法
【5月更文挑战第15天】线性搜索从数组一端按顺序遍历,直到找到目标元素,平均和最坏情况的时间复杂度均为O(N)。二分查找适用于排序数组,通过比较中间元素快速定位目标,最佳、平均和最坏情况的时间复杂度都是O(logN)。
16 6
|
10天前
|
算法 C++
c++算法学习笔记 (21) STL
c++算法学习笔记 (21) STL
|
10天前
|
算法 C++
c++算法学习笔记 (20) 哈希表
c++算法学习笔记 (20) 哈希表
|
10天前
|
算法 C++
c++算法学习笔记 (19) 堆
c++算法学习笔记 (19) 堆
|
10天前
|
人工智能 算法 C++
c++算法学习笔记 (18) 约数
c++算法学习笔记 (18) 约数
|
10天前
|
人工智能 算法 C++
c++算法学习笔记 (17) 质数
c++算法学习笔记 (17) 质数
|
10天前
|
算法 C++
c++算法学习笔记 (16) 并查集
c++算法学习笔记 (16) 并查集
|
10天前
|
算法 C++
c++算法学习笔记 (15) 单调栈与单调队列
c++算法学习笔记 (15) 单调栈与单调队列
|
10天前
|
算法 C++
c++算法学习笔记 (14) 栈与队列
c++算法学习笔记 (14) 栈与队列
|
10天前
|
算法 C++
c++算法学习笔记 (13) 链表
c++算法学习笔记 (13) 链表