问题描述
小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]
题目背景
本题目涉及到搜索引擎中的一个关键技术——倒排索引。倒排索引是一种索引数据结构,广泛用于信息检索系统中,如搜索引擎、数据库等。通过构建倒排索引,可以高效地查询包含特定关键词的所有文档或帖子。
给定两个已经排序好的倒排链数组 a 和 b,代表两个不同单词在多个帖子中的出现情况。任务是找出同时包含这两个单词的帖子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 外,没有使用额外的空间,保持了较低的空间复杂度。
性能优化:通过从后向前遍历,避免了不必要的排序操作,提高了算法的执行效率。
扩展性:如果需要处理更多的倒排链,可以考虑使用哈希表或其他数据结构来进一步优化查找速度。
具体应用
搜索引擎:倒排索引是搜索引擎的核心技术之一,通过高效地查找包含特定关键词的文档或帖子,提高用户的搜索体验。数据处理:在大数据处理场景中,双指针法可以用于快速查找两个有序数据集的交集,适用于各种数据匹配和过滤任务。
算法设计:理解和掌握双指针法及其变种,有助于在其他算法设计中灵活运用,解决类似的问题。
通过这次题目的解决,我们不仅巩固了对倒排索引和双指针法的理解,还学会了如何高效地处理有序数组的交集问题。这种技能在实际开发中非常有用,尤其是在涉及大量数据处理和搜索优化的场景中。