解题思路
题目要求我们找到两个倒排索引列表的交集,并且将结果按降序排列输出。这里的两个倒排链其实就是两个排序好的整数数组,表示含有特定关键词的帖子ID。我们的目标是找到同时包含这两个关键词的所有帖子ID,并且按照从大到小的顺序返回。
1. 理解倒排索引的特点
倒排索引本质上是一个单词到包含该单词的文档ID(帖子ID)之间的映射。每个关键词都会对应一个按升序排列的帖子ID列表。比如,假设我们有以下两个关键词的倒排链:
- 关键词A的倒排链:
[1, 2, 3, 7] - 关键词B的倒排链:
[2, 5, 7]
我们的任务就是找出这两个列表的交集,即同时包含关键词A和关键词B的帖子ID,最后返回的结果是[7, 2](从大到小排序)。
2. 交集问题
这道题目本质上是一个典型的两个有序数组的交集问题。由于输入的两个列表是已经排好序的,我们可以利用这个有序性,采用双指针的方式高效地求解交集。
3. 双指针法
双指针是一种在两个有序数组中寻找交集的经典方法。通过设置两个指针分别指向两个数组的起始位置,我们逐步比较数组中的元素,并根据比较结果来移动指针,直到遍历完数组为止。具体步骤如下:
- 初始化两个指针
i和j,分别指向数组a和数组b的开始位置。 - 如果
a[i] == b[j],说明a[i]和b[j]是相同的帖子ID,因此我们可以将它加入结果列表中,并同时移动两个指针i++和j++。 - 如果
a[i] < b[j],说明a[i]比b[j]小,由于两个数组是升序排列的,所以a[i]不可能出现在b[j]后面,因此我们需要将指针i向前移动,即i++。 - 如果
a[i] > b[j],说明a[i]比b[j]大,同样,由于两个数组是升序排列的,b[j]不可能出现在a[i]后面,因此我们需要将指针j向前移动,即j++。
通过这种方式,我们可以高效地找到两个数组的交集。
4. 降序排序
在找到交集后,题目要求我们返回的结果需要按降序排列。因为两个输入数组是升序排列的,而交集的部分自然也会是升序排列的,因此只需要在返回结果前,调用Collections.reverse(result)将结果逆序即可。
5. 总结
- 双指针法:通过双指针遍历两个已排序的数组,找到交集部分。
- 逆序输出:由于题目要求按降序排列结果,所以找到交集后需要进行逆序处理。
具体步骤
-
初始化指针:我们分别用
i和j指向两个数组a和b的开始位置。 -
逐步比较:通过比较
a[i]和b[j]的值:- 如果相等,将该值加入结果数组,并同时移动两个指针。
- 如果
a[i] < b[j],说明a[i]不在b中,指针i向后移动。 - 如果
a[i] > b[j],说明b[j]不在a中,指针j向后移动。
-
处理结束:当我们遍历完两个数组后,结果数组即为交集,按升序排列。我们使用
Collections.reverse(result)来将结果数组逆序,得到降序排列的结果。
代码实现
下面是基于上述思路的代码实现:
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;
int sizeA = a.size();
int sizeB = b.size();
// 双指针遍历两个数组
while (i < sizeA && j < sizeB) {
int valA = a.get(i);
int valB = b.get(j);
if (valA == valB) {
// 找到相同的帖子ID,加入结果并同时移动两个指针
result.add(valA);
i++;
j++;
} else if (valA < valB) {
// 如果a[i]小于b[j],说明a[i]不在b中,指针i向后移动
i++;
} else {
// 如果a[i]大于b[j],说明b[j]不在a中,指针j向后移动
j++;
}
}
// 逆序结果列表,得到降序排列
Collections.reverse(result);
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)));
}
}
复杂度分析
- 时间复杂度:
O(n + m),其中n和m分别是数组a和b的长度。由于我们通过双指针一次遍历两个数组,因此时间复杂度是线性的。 - 空间复杂度:
O(k),其中k是两个数组的交集大小。我们需要额外的空间存储交集结果。最坏情况下,两个数组完全相同,结果列表的大小为n(或m),所以空间复杂度为O(n)。
总结
这道题目利用了倒排索引的基本概念,并通过双指针法高效地找出了两个排序数组的交集。由于输入的数组是排序的,我们可以通过双指针避免了不必要的遍历,降低了时间复杂度。此外,通过简单的逆序操作,我们也能满足题目对于输出顺序的要求。这种解法非常适合处理大规模数据集,且易于理解和实现。