每天一小步 | 豆包MarsCode AI刷题

165 阅读4分钟

使用倒排索引优化搜索引擎结果

问题背景

小S正在帮助朋友们开发一个高效的搜索引擎。为了让用户更快速地找到感兴趣的帖子,她决定使用 倒排索引 来加速搜索过程。倒排索引是一种常见的文本检索技术,其中每个单词都与包含该单词的文档ID(或帖子ID)进行关联。这样,查询某个单词时,只需查找该单词对应的文档ID列表,而不需要重新遍历整个数据库或文本。

倒排索引的基本原理

假设我们有一组帖子,每个帖子都包含一些单词。倒排索引的构建方式是:为每个单词记录一个列表,列表中存储该单词出现的帖子ID,并且这些ID按从小到大的顺序排列。

例如,假设我们有以下帖子:

  • 帖子1:内容是“夏天 海滩”
  • 帖子2:内容是“海滩 夏天”
  • 帖子3:内容是“夏天 沙滩”

倒排索引会记录如下:

  • “夏天” -> [1, 2, 3]
  • “海滩” -> [1, 2]
  • “沙滩” -> [3]

问题描述

现在,我们需要根据两个给定的单词(例如“夏天”和“海滩”),找出包含这两个单词的所有帖子,并且将这些帖子按从大到小的顺序输出。这相当于找出两个倒排链的交集。

解题思路

为了找出两个倒排链的交集并按要求排序,我们可以采用如下步骤:

  1. 使用双指针法:同时遍历两个倒排链数组 ab,找到它们的交集。如果两个元素相同,则将该元素加入结果列表;如果不相同,移动指针指向较小的元素。
  2. 排序:由于题目要求输出的帖子ID按从大到小的顺序排列,我们可以在找到交集后,将结果按降序排列。

代码实现

import java.util.*;

public class Main {
    public static List<Integer> solution(List<Integer> a, List<Integer> b) {
        // 初始化结果列表
        List<Integer> result = new ArrayList<>();
        
        // 使用两个指针遍历两个列表,找到交集
        int i = 0, j = 0;
        while (i < a.size() && j < b.size()) {
            if (a.get(i).equals(b.get(j))) {
                // 如果找到相同的元素,加入结果列表
                result.add(a.get(i));
                i++;
                j++;
            } else if (a.get(i) < b.get(j)) {
                i++;
            } else {
                j++;
            }
        }
        
        // 将结果列表按从大到小的顺序排序
        Collections.sort(result, Collections.reverseOrder());
        
        return result;
    }

    public static void main(String[] args) {
        // 测试用例
        System.out.println(solution(Arrays.asList(1, 2, 3, 7), Arrays.asList(2, 5, 7)).equals(Arrays.asList(7, 2)));
        System.out.println(solution(Arrays.asList(1, 4, 8, 10), Arrays.asList(2, 4, 8, 10)).equals(Arrays.asList(10, 8, 4)));
        System.out.println(solution(Arrays.asList(3, 5, 9), Arrays.asList(1, 4, 6)).equals(Collections.emptyList()));
        System.out.println(solution(Arrays.asList(1, 2, 3), Arrays.asList(1, 2, 3)).equals(Arrays.asList(3, 2, 1)));
    }
}

代码分析

1. 使用双指针法找交集

我们用两个指针 ij 分别指向倒排链 ab 的开头,逐一比较两个列表中的元素。如果 a[i]b[j] 相等,说明该帖子ID在两个列表中都出现了,可以加入到结果列表中;如果 a[i] 小于 b[j],说明 a[i] 不可能出现在 b[j] 之后,因此我们可以移动指针 i;同理,如果 a[i] 大于 b[j],则移动指针 j

2. 排序

根据题目要求,交集的帖子ID需要按从大到小的顺序输出,因此我们在获得交集后使用 Collections.sort(result, Collections.reverseOrder()) 对结果列表进行降序排序。

3. 时间复杂度
  • 遍历两个列表的时间复杂度为 O(n + m),其中 nm 分别是列表 ab 的长度。
  • 排序操作的时间复杂度为 O(k log k),其中 k 是交集列表的长度。

因此,总时间复杂度是 O(n + m + k log k),其中 k 是交集元素的个数。

4. 空间复杂度

我们使用了一个额外的列表 result 来存储交集元素,因此空间复杂度为 O(k)

示例解析

示例1

输入:

a = [1, 2, 3, 7], b = [2, 5, 7]

交集是 [2, 7],排序后得到 [7, 2],因此输出:

[7, 2]

示例2

输入:

a = [1, 4, 8, 10], b = [2, 4, 8, 10]

交集是 [4, 8, 10],排序后得到 [10, 8, 4],因此输出:

[10, 8, 4]

示例3

输入:

a = [3, 5, 9], b = [1, 4, 6]

交集为空,因此输出:

[]

示例4

输入:

a = [1, 2, 3], b = [1, 2, 3]

交集是 [1, 2, 3],排序后得到 [3, 2, 1],因此输出:

[3, 2, 1]

结语

通过这道题目,我们学习了如何使用倒排索引及其交集操作来优化搜索引擎的查询效率。掌握双指针法、排序和集合操作是提升算法能力的关键。在实际的应用中,倒排索引和交集操作经常用于搜索引擎、推荐系统等领域,因此理解这些技术对于构建高效系统至关重要。