问题描述
小S正在帮助她的朋友们建立一个搜索引擎。为了让用户能够更快地找到他们感兴趣的帖子,小S决定使用倒排索引。倒排索引的工作原理是:每个单词都会关联一个帖子ID的列表,这些帖子包含该单词,且ID按从小到大的顺序排列。
例如,单词“夏天”可能出现在帖子1、帖子3和帖子7中,那么这个单词的倒排链就是 [1, 3, 7]。如果用户想同时找到包含“夏天”和“海滩”的帖子,小S需要找出两个倒排链的交集,且将结果按照从大到小的顺序输出。现在,给定两个单词的倒排链数组 a 和 b,请你帮助小S找出同时包含这两个单词的帖子ID,并按从大到小的顺序返回结果。
解法一:
`#include
#include
#include <unordered_set>
#include
using namespace std;
vector solution(vector &a, vector &b) { vector result; unordered_set hashSet;
// 将数组 a 的元素存入哈希表 for (int num : a) { hashSet.insert(num); }
// 遍历数组 b,检查元素是否存在于哈希表中 for (int num : b) { if (hashSet.find(num) != hashSet.end()) { result.push_back(num); // 为了避免重复添加相同的元素,从哈希表中删除该元素 hashSet.erase(num); } }
// 反转结果数组,使其按从大到小的顺序排列 sort(result.rbegin(), result.rend());
return result; }
int main() { vector a1 = {1, 2, 3, 7}; vector b1 = {2, 5, 7}; vector res1 = solution(a1, b1); cout << (res1 == vector{7, 2}) << endl;
vector a2 = {1, 4, 8, 10}; vector b2 = {2, 4, 8, 10}; vector res2 = solution(a2, b2); cout << (res2 == vector{10, 8, 4}) << endl;
vector a3 = {3, 5, 9}; vector b3 = {1, 4, 6}; vector res3 = solution(a3, b3); cout << (res3 == vector{}) << endl;
vector a4 = {1, 2, 3}; vector b4 = {1, 2, 3}; vector res4 = solution(a4, b4); cout << (res4 == vector{3, 2, 1}) << endl;
return 0; }`
方法二:
`#include
#include
#include // for std::reverse
using namespace std;
vector solution(vector& a, vector& b) { vector result; int i = 0, j = 0;
// 遍历数组 a 和 b
while (i < a.size() && j < b.size()) {
if (a[i] == b[j]) {
// 找到交集元素,加入结果数组
result.push_back(a[i]);
i++;
j++;
} else if (a[i] < b[j]) {
// a 中的元素较小,移动 a 的指针
i++;
} else {
// b 中的元素较小,移动 b 的指针
j++;
}
}
// 反转结果数组,使其按从大到小的顺序排列
reverse(result.begin(), result.end());
return result;
}
int main() { vector a1 = {1, 2, 3, 7}; vector b1 = {2, 5, 7}; vector res1 = solution(a1, b1); cout << (res1 == vector{7, 2}) << endl;
vector<int> a2 = {1, 4, 8, 10};
vector<int> b2 = {2, 4, 8, 10};
vector<int> res2 = solution(a2, b2);
cout << (res2 == vector<int>{10, 8, 4}) << endl;
vector<int> a3 = {3, 5, 9};
vector<int> b3 = {1, 4, 6};
vector<int> res3 = solution(a3, b3);
cout << (res3 == vector<int>{}) << endl;
vector<int> a4 = {1, 2, 3};
vector<int> b4 = {1, 2, 3};
vector<int> res4 = solution(a4, b4);
cout << (res4 == vector<int>{3, 2, 1}) << endl;
return 0;}
知识点
-
哈希表 (
unordered_set) :unordered_set是一个无序集合,支持平均常数时间复杂度的插入和查找操作。- 使用
insert方法将元素插入哈希表。 - 使用
find方法查找元素,如果找到则返回指向该元素的迭代器,否则返回end()。 - 使用
erase方法删除元素,避免重复添加相同的元素。
-
逆向排序:
- 使用
sort(result.rbegin(), result.rend())将结果数组按从大到小的顺序排序。
- 使用
-
迭代器:
rbegin()和rend()分别返回逆向迭代器,指向容器的最后一个元素和第一个元素之前的位置-
比较
-
时间复杂度:
- 方法一:时间复杂度为 O(n+m)O(n+m),其中 nn 和 mm 分别是数组
a和b的长度。这是因为插入和查找哈希表的操作都是平均常数时间复杂度。 - 方法二:时间复杂度为 O(n+m)O(n+m),其中 nn 和 mm 分别是数组
a和b的长度。这是因为每个元素最多只会被访问一次。
- 方法一:时间复杂度为 O(n+m)O(n+m),其中 nn 和 mm 分别是数组
-
空间复杂度:
- 方法一:空间复杂度为 O(n)O(n),因为需要额外的空间来存储哈希表。
- 方法二:空间复杂度为 O(1)O(1),因为只使用了常数级别的额外空间。
-
适用场景:
- 方法一:适用于数组较大且需要快速查找的情况。
- 方法二:适用于数组已经排序且不需要额外空间的情况。
结论
- 方法一 使用哈希表,适合处理较大的数据集,查找速度快,但需要额外的空间。
- 方法二 使用双指针法,适合处理已经排序的数组,不需要额外空间,但查找速度稍慢。
ai练习
1. 理论学习
利用AI进行理论学习
- 课程推荐:使用AI工具推荐适合你的算法课程。例如,你可以输入你的背景和目标,AI会为你推荐合适的在线课程或书籍。
- 概念解释:当你遇到不懂的概念或算法时,可以使用AI工具获取详细的解释和示例。例如,你可以询问“什么是动态规划?”或“如何实现二分查找?”。
- 视频教程:AI可以推荐相关的视频教程,帮助你通过视觉和听觉的方式更好地理解复杂的算法概念。
2. 实践练习
利用AI进行实践练习
- 题库推荐:使用AI工具推荐适合你当前水平的算法题目。例如,你可以输入你的技能水平,AI会为你推荐适合的LeetCode题目。
- 代码生成:当你卡在一个问题上时,可以使用AI生成初步的代码框架,帮助你快速上手。例如,你可以询问“生成一个二分查找的代码框架”。
- 代码调试:使用AI工具帮助你调试代码。例如,你可以输入你的代码和错误信息,AI会给出可能的解决方案。
3. 反馈循环
利用AI进行反馈和评估
- 代码审查:使用AI工具对你的代码进行审查,指出潜在的问题和优化建议。例如,你可以上传你的代码,AI会给出详细的代码审查报告。
- 性能评估:使用AI工具评估你的算法性能,帮助你了解时间和空间复杂度。例如,你可以询问“我的算法的时间复杂度是多少?”。
- 错误分析:当你提交的代码未能通过某些测试用例时,使用AI工具帮助你分析错误原因。例如,你可以上传失败的测试用例,AI会给出可能的原因和解决方案。
4. 持续改进
利用AI进行持续改进
- 学习路径规划:使用AI工具规划你的学习路径,根据你的进度和目标推荐下一步的学习内容。例如,你可以输入你的长期目标,AI会为你制定一个详细的学习计划。
- 定期评估:使用AI工具定期评估你的进步,帮助你识别弱点并进行针对性的训练。例如,你可以设置每周一次的评估,AI会生成你的进步报告并提出改进建议。
- 社区互动:利用AI工具连接到算法学习社区,与其他学习者交流经验和问题。例如,你可以加入AI推荐的算法学习群组,参与讨论和互助。