小S的倒排索引题中的Python知识点总结 | 豆包MarsCode AI刷题

55 阅读6分钟

小S的倒排索引题中的Python知识点总结

0.背景引入

最近笔者在豆包 MarsCode AI 题库刷题的时候, 碰到一个算法题目,其实这个题本身不难, 但是我发现其中有一些知识点,让我觉得值得和新手朋友们分享一下。

就是:Python里,如何实现列表的交集?以及如何实现列表的排序?

(其实笔者在刚学习Python的时候,也在书本上看过这些语法例子,但是因为刷题,我又加强了一下记忆。)

1.题目复现

先来看一下这道算法题的原题:

问题描述
小S正在帮助她的朋友们建立一个搜索引擎。为了让用户能够更快地找到他们感兴趣的帖子,小S决定使用倒排索引。
倒排索引的工作原理是:每个单词都会关联一个帖子ID的列表,这些帖子包含该单词,且ID按从小到大的顺序排列。
例如,单词“夏天”可能出现在帖子1、帖子3和帖子7中,那么这个单词的倒排链就是 [1, 3, 7]。
如果用户想同时找到包含“夏天”和“海滩”的帖子,小S需要找出两个倒排链的交集,且将结果按照从大到小的顺序输出。

现在,给定两个单词的倒排链数组 ab,请你帮助小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最基础知识点:列表交集的实现列表排序的实现

笔者觉得,与其看书本或者听别人总结一些常见的编程语法和技巧,倒不如我们动手多实践一下,刷刷算法题,这样才能更好地掌握这些知识点。