【一个小实验】找出两个数组中相同的元素
2015-08-02 16:31
351 查看
搬运自洒家的QQ空间(不要问我问什么用空间,懒就一个字......),转载请注明出处。
在实际中,我们经常需要找出两个数组A和B中相同的元素(事实上,在面试中或者做题的时候大家也应该遇到过很多这样的题目)。
通常的做法自然是两层for循环,从A中取一个元素α,在B中遍历查找这个α。设A/B的长度分别为N和M。那这个算法的时间复杂度将达到N*M。如果N和M都很大的情况下(比如都是几万),消耗时间通常是我们不能忍受的。
有木有更好的办法也?
恰好这两天在重温《C++ primer》,看到关联容器的时候我就想,有没有可能将其中较小的一个数组(比如B)中的元素全部放进一个HashSet中,然后再遍历另一个数组(A)。通过hash函数来确定是否包含当前数组A中的元素α?
因为,根据Hash函数的特点,只要构造得足够好,那么在Set中查找α的时间复杂度通常是常数级的(甚至是O(1))。
那么整个算法的时间复杂度最好的情况能达到O(N)。
巨大的提升啊~~~~
于是就有了下面这个小实验。
当最大长度等于1W的时候():
当最大长度等于5W的时候:
可以看到,通过hashSet来进行查找,耗时仅为两个for循环的数百分之一。超级巨大的性能提升有木有。感觉get到了什么不得了的技能呢。
在实际中,我们经常需要找出两个数组A和B中相同的元素(事实上,在面试中或者做题的时候大家也应该遇到过很多这样的题目)。
通常的做法自然是两层for循环,从A中取一个元素α,在B中遍历查找这个α。设A/B的长度分别为N和M。那这个算法的时间复杂度将达到N*M。如果N和M都很大的情况下(比如都是几万),消耗时间通常是我们不能忍受的。
有木有更好的办法也?
恰好这两天在重温《C++ primer》,看到关联容器的时候我就想,有没有可能将其中较小的一个数组(比如B)中的元素全部放进一个HashSet中,然后再遍历另一个数组(A)。通过hash函数来确定是否包含当前数组A中的元素α?
因为,根据Hash函数的特点,只要构造得足够好,那么在Set中查找α的时间复杂度通常是常数级的(甚至是O(1))。
那么整个算法的时间复杂度最好的情况能达到O(N)。
巨大的提升啊~~~~
于是就有了下面这个小实验。
#include <iostream> #include <vector> #include <ctime> using namespace std; int main() { /* 这里我们用两个Vector来模拟两个数组。数组最大长度为N */ vector<int> vec;//长的那个 vector<int> vec2;//短的那个,这里被设定只保存偶数,也就是vec长度的一半 //生成测试数据 for (int i = 0; i < 50000; i++) { vec.push_back(i); if (i % 2 == 0) vec2.push_back(i); } clock_t start_time = clock(); { //被测试代码 cout << "-----------开始测试段 1 " << endl; //记录下两个VECTOR中重复的数字个数,下同 long counter = 0; //两个for循环检测 for (int i = 0; i < vec.size(); i++) for (int j = 0; j < vec2.size(); j++) { if (vec2[j] == vec[i]) counter++; } cout << "找到重复个数:" << counter << endl; } clock_t end_time = clock(); //------------------------------------- clock_t start_time2 = clock(); { cout << "------------开始测试段 2 " << endl; long counter = 0; //在C++ 11 STL 中,unordered_set就是一个HashSet。因此不需要我们再去手动写一个 unordered_set<int> mSet; //将较短的vector中的元素复制到Set中去 for (int i = 0; i < vec2.size(); i++) { mSet.insert(vec2[i]); } //遍历较长的那个数组 for (int i = 0; i < vec.size(); i++) { //注意调用set的find方法,这个方法会通过计算Hash值来比较 if (mSet.end() == mSet.find(vec[i])) counter++; } cout << "找到重复个数:" << counter << endl; } clock_t end_time2 = clock(); cout << "测试段1耗时: " << static_cast<double>(end_time - start_time) / CLOCKS_PER_SEC * 1000 << "ms" << endl;//输出运行时间 cout << "测试段2耗时: " << static_cast<double>(end_time2 - start_time2) / CLOCKS_PER_SEC * 1000 << "ms" << endl;//输出运行时间 return 0; }实验结果:
当最大长度等于1W的时候():
当最大长度等于5W的时候:
可以看到,通过hashSet来进行查找,耗时仅为两个for循环的数百分之一。超级巨大的性能提升有木有。感觉get到了什么不得了的技能呢。
相关文章推荐
- POJ 2771 Guardian of Decency
- UICollectionView学习
- CSS基础-33面向对象的 CSS 课程概要,要反复看视频
- CSS基础-34Less 介绍和应用,需要反复看视频
- 重建二叉树
- 程序随笔:汉诺塔
- iOS获取键盘高度的方法
- 28个不得不看的经典编程算法!!
- BFS-POJ-3126-Prime Path
- mybatis性能优化之减少数据库连接
- poj3616 dp
- Same Tree
- UE4信息交互-关卡蓝图内的交互
- 4步win7下简单FTP服务器搭建(试验成功)
- CSS基础-32CSS瀑布流效果
- OC学习笔记四-1 内存管理(Retain-Release)
- POJ_1651_MultiplicationPuzzle
- windows学习笔记二 --滚动条的绘制
- 作业配置规范文档[MS SQL]
- 作为程序员之正则表达式