AI刷题 35.小S的倒排索引 | 豆包MarsCode AI 刷题

176 阅读5分钟

问题描述

小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]


题目背景

本题目涉及到搜索引擎中的一个关键技术——倒排索引。倒排索引是一种索引数据结构,广泛用于信息检索系统中,如搜索引擎、数据库等。通过构建倒排索引,可以高效地查询包含特定关键词的所有文档或帖子。

给定两个已经排序好的倒排链数组 ab,代表两个不同单词在多个帖子中的出现情况。任务是找出同时包含这两个单词的帖子ID,并按从大到小的顺序返回结果。

思路分析

双指针法:

由于输入的两个数组已经是有序的(升序),可以采用双指针的方法来查找两个数组的公共元素。初始化两个指针分别指向两个数组的末尾。

比较并移动指针:比较两个指针所指向的元素:

如果相等,则将该元素加入结果集中,并将两个指针都向前移动一位。 如果 a 中的元素大于 b 中的元素,则将 a 的指针向前移动一位。 否则,将 b 的指针向前移动一位。

终止条件:

当任意一个指针移动至数组头部时,停止搜索。

结果处理:

因为是从后往前遍历,所以收集到的结果已经是按从大到小排序的,无需额外排序。

样例分析:

以样例1为例 初始化指针 i 指向 a 的最后一个元素 7,指针 j 指向 b 的最后一个元素 7。

比较 a[i] 和 b[j]: a[3] == b[2],即 7 == 7,将 7 添加到结果中,然后 i-- 和 j--。 更新指针 i 指向 3,指针 j 指向 5。

比较 a[i] 和 b[j]: a[2] < b[1],即 3 < 5,将 j--。 更新指针 j 指向 2。

比较 a[i] 和 b[j]: a[2] == b[1],即 3 == 2,将 2 添加到结果中,然后 i-- 和 j--。 更新指针 i 指向 1,指针 j 指向 0。

比较 a[i] 和 b[j]: a[1] < b[0],即 2 < 2,将 j--。 指针 j 已经小于 0,结束循环。

关键点

双指针法:通过两个指针从数组末尾开始向前遍历,确保找到的交集元素自然就是按从大到小的顺序排列的。

时间复杂度:由于每个指针最多遍历一次数组,时间复杂度为 O(n + m),其中 n 和 m 分别是数组 a 和 b 的长度。

空间复杂度:除了存储结果的 vector 外,没有使用额外的空间,因此空间复杂度为 O(min(n, m)),其中 min(n, m) 是两个数组中较短的那个数组的长度。

代码分析

头文件和命名空间

    #include <iostream>
    #include <vector>
    using namespace std;

引入了标准输入输出流和向量容器。 使用 std 命名空间,避免每次调用标准库函数时都需要加上 std:: 前缀。

解决方案函数 solution

    vector<int> solution(vector<int>& a, vector<int>& b) {
    vector<int> result;
    int i = a.size() - 1;
    int j = b.size() - 1;

    while (i >= 0 && j >= 0) {
        if (a[i] == b[j]) {
            result.push_back(a[i]);
            --i;
            --j;
        } else if (a[i] > b[j]) {
            --i;
        } else {
            --j;
        }
    }

    return result;
}

参数:两个引用传递的 vector 类型的数组 a 和 b。

返回值:一个 vector 类型的结果数组,存储两个数组的交集。

初始化:两个指针 i 和 j 分别指向数组 a 和 b 的最后一个元素。

循环:当两个指针都未到达数组头部时,继续循环。

相等情况:如果 a[i] 等于 b[j],说明找到了一个共同元素,将其添加到结果数组 result 中,并将两个指针都向前移动一位。

a[i] 大于 b[j]:将指针 i 向前移动一位。 a[i] 小于 b[j]:将指针 j 向前移动一位。

返回结果:返回存储交集元素的结果数组 result。

心得分析

空间优化:除了存储结果的 vector 外,没有使用额外的空间,保持了较低的空间复杂度。

性能优化:通过从后向前遍历,避免了不必要的排序操作,提高了算法的执行效率。

扩展性:如果需要处理更多的倒排链,可以考虑使用哈希表或其他数据结构来进一步优化查找速度。

具体应用

搜索引擎:倒排索引是搜索引擎的核心技术之一,通过高效地查找包含特定关键词的文档或帖子,提高用户的搜索体验。

数据处理:在大数据处理场景中,双指针法可以用于快速查找两个有序数据集的交集,适用于各种数据匹配和过滤任务。

算法设计:理解和掌握双指针法及其变种,有助于在其他算法设计中灵活运用,解决类似的问题。

通过这次题目的解决,我们不仅巩固了对倒排索引和双指针法的理解,还学会了如何高效地处理有序数组的交集问题。这种技能在实际开发中非常有用,尤其是在涉及大量数据处理和搜索优化的场景中。