小S的倒排索引题中的Python知识点总结
0.背景引入
最近笔者在豆包 MarsCode AI 题库刷题的时候, 碰到一个算法题目,其实这个题本身不难, 但是我发现其中有一些知识点,让我觉得值得和新手朋友们分享一下。
就是:Python里,如何实现列表的交集?以及如何实现列表的排序?
(其实笔者在刚学习Python的时候,也在书本上看过这些语法例子,但是因为刷题,我又加强了一下记忆。)
1.题目复现
先来看一下这道算法题的原题:
问题描述
小S正在帮助她的朋友们建立一个搜索引擎。为了让用户能够更快地找到他们感兴趣的帖子,小S决定使用倒排索引。
倒排索引的工作原理是:每个单词都会关联一个帖子ID的列表,这些帖子包含该单词,且ID按从小到大的顺序排列。
例如,单词“夏天”可能出现在帖子1、帖子3和帖子7中,那么这个单词的倒排链就是 [1, 3, 7]。
如果用户想同时找到包含“夏天”和“海滩”的帖子,小S需要找出两个倒排链的交集,且将结果按照从大到小的顺序输出。
现在,给定两个单词的倒排链数组 a 和 b,请你帮助小S找出同时包含这两个单词的帖子ID,并按从大到小的顺序返回结果。
测试样例
输入:a = [1, 2, 3, 7], b = [2, 5, 7]
输出:[7, 2]
输入:a = [1, 4, 8, 10], b = [2, 4, 8, 10]
输出:[10, 8, 4]
输入:a = [3, 5, 9], b = [1, 4, 6]
输出:[]
输入:a = [1, 2, 3], b = [1, 2, 3]
输出:[3, 2, 1]
2. 题目解析
虽然这篇文章,笔者主要是想讨论一下这道题相关的知识点,不过我们还是先来理清一下这道题的解题思路和步骤,这样子有助于我们可以深刻理解其中的知识点。
2.1.解题思路
其实这道题非常简单,最主要就是找到同时包含给定的列表a和b元素的元素是什么,并且按照从大到小的顺序输出。 因此,我们可以:
- step1:找到a和b的交集,并且把这个交集存到我们自己定义的列表c里
- step2:对c里面的元素进行排序,再按照从大到小的顺序返回结果
2.2.代码编写及其知识点讲解
2.2.1.step 1:如何实现a和b的交集?
应该会有一些朋友会说:“直接用a&b就可以了”。原本笔者也是这么想的,但是这样子做会报出以下错误:
TypeError: unsupported operand type(s) for &: 'list' and 'list'
这个错误就是说,我们不能直接对列表进行交集操作。因为在Python里,列表并没有被设计出专门的集合运算功能,如交集、并集和差集等。
所以我们先要把列表a和b转化成集合a和b,再进行交集操作。 也就是:
a=set(a)
b=set(b)
c=a & b
2.2.2.step 2:如何对列表c进行排序?
我们可以使用sorted()函数对列表c进行排序。
sorted()函数的语法如下:
sorted(iterable, key=None, reverse=False)
其中:
- iterable:可迭代对象。可以是列表、元组、字典、集合等。
而根据上述步骤,我们可以得到如下的代码:
def solution(a, b):
# write code here
a=set(a)
b=set(b)
c=a & b
c=list(c)
c=sorted(c)[::-1]
return c
而刚刚上面又说了:sorted()函数里面有一个reverse参数,这个参数默认值为False,也就是升序排序。
在这道题里,我们也可以通过设定c=sorted(c,reverse=True),来实现从大到小的排序。
def solution(a, b):
# write code here
a=set(a)
b=set(b)
c=a & b
c=list(c)
c=sorted(c,reverse=True)
return c
if __name__ == '__main__':
print(solution([1, 2, 3, 7], [2, 5, 7]) == [7, 2]) #True
print(solution([1, 4, 8, 10], [2, 4, 8, 10]) == [10, 8, 4]) #True
print(solution([3, 5, 9], [1, 4, 6]) == []) #True
print(solution([1, 2, 3], [1, 2, 3]) == [3, 2, 1]) #True
上述的解法是被允许的。
但是,有的朋友会说:我记得,Python里面还有一个函数是sort(),这个函数和sorted()有什么区别呢?
我们可以尝试把刚刚上面那个代码里的c=sorted(c)[::-1],改成c.sort()[::-1],看看会出现什么情况。
结果如下:
TypeError: 'NoneType' object is not subscriptable
上面的错误就是说:NoneType对象是不可订阅的。
看来应该是因为c.sort()产生了错误,可是为什么会造成这个错误呢?
我们可以使用debug工具去看看。
给c.sort()这句代码设置断点之后,可以发现:
当c调用了列表自带的sort()函数之后,c的值就会变成了None,因此就造成c无法被切片查值,导致报错。
那我们是否有一些解决方法呢?
当然有!通过查阅help文档可以发现,sort()的语法为下:
sort(*, key=None, reverse=False)
其中:
- key:可选参数,用于指定一个函数,该函数将在排序之前应用于每个元素。
- reverse:可选参数,用于指定是否按降序排序。
原来sort()也有reverse参数,所以我们可以试试设置sort()里面的reverse参数为True:
def solution(a, b):
# write code here
a=set(a)
b=set(b)
c=a & b
c=list(c)
c.sort(reverse=True)
return c
if __name__ == '__main__':
print(solution([1, 2, 3, 7], [2, 5, 7]) == [7, 2]) #True
print(solution([1, 4, 8, 10], [2, 4, 8, 10]) == [10, 8, 4]) #True
print(solution([3, 5, 9], [1, 4, 6]) == []) #True
print(solution([1, 2, 3], [1, 2, 3]) == [3, 2, 1]) #True
可见,这样子输出就正常了。
而关于sort()和sorted()的区别是?
总的来说,sort()是list的一个方法,sorted()是python的一个内置函数。所以我想,这也是为什么,我们在使用sort()时,不需要把值传给另外一个变量(比如d=c.sort()),并且就算我们这么做,也会报错NoneType。
3. 总结
通过上面小S的倒排索引题的例子,笔者一共为大家总结了两个Python最基础知识点:列表交集的实现和列表排序的实现。
笔者觉得,与其看书本或者听别人总结一些常见的编程语法和技巧,倒不如我们动手多实践一下,刷刷算法题,这样才能更好地掌握这些知识点。