“青训营X豆包MarsCode 技术训练营第五课 | 豆包MarsCode AI 刷题

97 阅读4分钟

问题描述

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


测试样例

样例1:

输入:a = [1, 2, 3, 7], b = [2, 5, 7]
输出:[7, 2]

样例2:

输入:a = [1, 4, 8, 10], b = [2, 4, 8, 10]
输出:[10, 8, 4]

样例3:

输入:a = [3, 5, 9], b = [1, 4, 6]
输出:[]

样例4:

输入:a = [1, 2, 3], b = [1, 2, 3]
输出:[3, 2, 1]

问题分析

题目要求我们从两个倒排索引的数组中找出它们的交集,并按从大到小的顺序输出交集的结果。倒排索引数组中已经保证了帖子ID的顺序是从小到大的,因此,我们的目标就是找出两个数组的交集,并且将交集的结果按从大到小排序。

解决方案

  1. 交集操作:我们需要找出两个列表(ab)的交集。可以利用两个指针分别遍历 ab 来实现交集的求解。

    • 由于 a 和 b 都是有序的,我们可以采用类似于归并排序的技巧,使用两个指针 i 和 j,分别指向数组 a 和 b
    • 如果 a[i] == b[j],则这个值是交集的一部分,加入结果并移动两个指针。
    • 如果 a[i] < b[j],则移动 i,否则移动 j
  2. 排序操作:交集的结果得到后,我们需要将结果按从大到小的顺序输出。

步骤

  1. 使用双指针方法计算两个数组的交集。
  2. 将交集数组反转(因为题目要求从大到小的顺序)。
  3. 输出反转后的交集结果。

代码实现

pythonCopy Code
def intersect_and_reverse(a, b):
    # 结果数组
    result = []
    
    # 双指针遍历
    i, j = 0, 0
    while i < len(a) and j < len(b):
        if a[i] == b[j]:
            result.append(a[i])
            i += 1
            j += 1
        elif a[i] < b[j]:
            i += 1
        else:
            j += 1
    
    # 结果反转,按从大到小顺序输出
    result.reverse()
    return result

# 测试用例
print(intersect_and_reverse([1, 2, 3, 7], [2, 5, 7]))  # 输出:[7, 2]
print(intersect_and_reverse([1, 4, 8, 10], [2, 4, 8, 10]))  # 输出:[10, 8, 4]
print(intersect_and_reverse([3, 5, 9], [1, 4, 6]))  # 输出:[]
print(intersect_and_reverse([1, 2, 3], [1, 2, 3]))  # 输出:[3, 2, 1]

解释

  1. 双指针方法

    • 我们使用两个指针 i 和 j,分别指向数组 a 和数组 b 的起始位置。

    • 每次比较 a[i] 和 b[j]

      • 如果相等,则说明这是两个数组的共同元素,加入结果数组,并同时移动两个指针。
      • 如果 a[i] < b[j],说明数组 a 中的当前元素小于 b 中的元素,移动指针 i
      • 如果 a[i] > b[j],说明数组 b 中的当前元素小于 a 中的元素,移动指针 j
    • 这个过程一直持续到有一个指针超出数组范围为止。

  2. 反转结果

    • 由于题目要求结果是按从大到小的顺序输出,我们在得到交集之后使用 result.reverse() 进行反转。

复杂度分析

  • 时间复杂度

    • 双指针遍历数组的时间复杂度为 O(min⁡(n,m))O(min(n,m)),其中 nn 和 mm 是数组 a 和 b 的长度。
    • 反转操作的时间复杂度为 O(k)O(k),其中 kk 是交集的大小。
    • 因此,总的时间复杂度为 O(min⁡(n,m)+k)O(min(n,m)+k),其中 kk 是交集大小。
  • 空间复杂度

    • 我们需要一个额外的数组 result 来存储交集,空间复杂度为 O(k)O(k),其中 kk 是交集的大小。

测试结果

  • 测试用例 1: 输入 [1, 2, 3, 7] 和 [2, 5, 7],交集为 [2, 7],反转后输出 [7, 2]
  • 测试用例 2: 输入 [1, 4, 8, 10] 和 [2, 4, 8, 10],交集为 [4, 8, 10],反转后输出 [10, 8, 4]
  • 测试用例 3: 输入 [3, 5, 9] 和 [1, 4, 6],没有交集,输出 []
  • 测试用例 4: 输入 [1, 2, 3] 和 [1, 2, 3],交集为 [1, 2, 3],反转后输出 [3, 2, 1]

这样,我们就完成了题目的要求。