做题笔记:求两个倒排链的交集
问题分析
本题要求计算两个倒排链(列表)a
和 b
的交集,并返回交集的结果按照从大到小的顺序排列。倒排索引常用于搜索引擎中,每个单词都关联一个帖子ID的列表,而交集操作通常是为了找到同时包含两个词的帖子。
关键要求:
- 找出两个倒排链中共同出现的帖子ID。
- 返回结果按从大到小的顺序排列。
解题思路
- 交集求解 :给定两个已排序的列表(倒排链),我们需要找出它们的交集。可以利用双指针法来高效地求解交集。因为两个列表都是升序排列的,我们从两个列表的末尾开始比较元素,如果它们相等,则将该元素添加到结果列表中。如果不相等,则移动指针指向较大的元素。
- 排序:由于题目要求返回的结果是按从大到小的顺序排列,我们可以在求交集的过程中就将结果添加到一个列表中,然后返回时可以直接得到正确的顺序。由于我们是从两个列表的末尾往前遍历,因此得到的交集本身是从大到小排列的。
- 时间复杂度 :由于两个列表都是有序的,双指针法的时间复杂度是
O(n + m)
,其中n
和m
分别是两个列表的长度。此方法相比直接进行集合运算要更加高效。
代码实现
csharp
import java.util.ArrayList;
import java.util.List;
public class Solution {
public static List<Integer> solution(List<Integer> a, List<Integer> b) {
// 初始化结果列表
List<Integer> result = new ArrayList<>();
// 双指针遍历两个列表
int i = a.size() - 1; // 指向列表a的末尾
int j = b.size() - 1; // 指向列表b的末尾
while (i >= 0 && j >= 0) {
if (a.get(i).equals(b.get(j))) {
// 如果两个指针指向的元素相同,加入结果列表
result.add(a.get(i));
i--;
j--;
} else if (a.get(i) > b.get(j)) {
// a的当前元素较大,移动指针i
i--;
} else {
// b的当前元素较大,移动指针j
j--;
}
}
return result; // 返回结果列表
}
}
代码解析
-
双指针初始化 :我们初始化两个指针
i
和j
,分别指向列表a
和b
的最后一个元素。因为我们要从后往前比较,以便得到按从大到小排序的结果。 -
遍历过程:
- 如果
a.get(i)
和b.get(j)
相等,说明这两个帖子ID是共同的,将其添加到结果列表中,然后分别移动指针i
和j
。 - 如果
a.get(i)
大于b.get(j)
,则说明列表a
中的当前元素较大,因此应该将i
向前移动,检查a
中下一个元素。 - 如果
b.get(j)
大于a.get(i)
,则说明列表b
中的当前元素较大,应该将j
向前移动,检查b
中下一个元素。
- 如果
-
返回结果 :最终的结果列表
result
中包含的是交集元素,且按从大到小的顺序排列。
时间复杂度分析
- 时间复杂度 :由于我们通过双指针法遍历两个列表,且每个元素最多被访问一次,因此时间复杂度为
O(n + m)
,其中n
和m
分别是两个列表的长度。 - 空间复杂度 :由于我们只需要一个额外的结果列表来存储交集元素,空间复杂度是
O(min(n, m))
,即结果列表的大小。
测试用例分析
考虑几个测试样例来验证代码的正确性。
样例1: 输入:
css
a = [1, 2, 3, 7], b = [2, 5, 7]
输出:
csharp
[7, 2]
- 交集为
2
和7
,按从大到小的顺序排列为[7, 2]
。
样例2: 输入:
css
a = [1, 4, 8, 10], b = [2, 4, 8, 10]
输出:
csharp
[10, 8, 4]
- 交集为
4, 8, 10
,按从大到小的顺序排列为[10, 8, 4]
。
样例3: 输入:
css
a = [3, 5, 9], b = [1, 4, 6]
输出:
css
[]
- 无交集,输出空列表
[]
。
样例4: 输入:
css
a = [1, 2, 3], b = [1, 2, 3]
输出:
csharp
[3, 2, 1]
- 交集为
1, 2, 3
,按从大到小的顺序排列为[3, 2, 1]
。