0
点赞
收藏
分享

微信扫一扫

(顺序表 链表 哈希表 红黑树的对比)lintcode简单607 · 两数之和 III-数据结构设计

无愠色 2022-04-29 阅读 15

题目

设计并实现一个 TwoSum 类。他需要支持以下操作:add 和 find。
add -把这个数添加到内部的数据结构。
find -是否存在任意一对数字之和等于这个值

每次操作的数的绝对值小于 10^6

样例

样例 1:

add(1);add(3);add(5);
find(4)//返回true
find(7)//返回false

分析

这道题是一道设计类的题
我们先来想最简单的想法

1.顺序表

add()函数,添加时直接放在尾部
时间复杂度O(1)

find()函数,查找时直接两两对比,查看是否能组合出来
时间复杂度O(n^2)

这个n^2 复杂度可以说是非常高了,我们想一下怎么来改进,如果是一个有序的数组,我们就可以利用双指针来做这道题

add()函数,每次添加的时候做一次插入排序
时间复杂度O(n)

思考一下我们可以利用二分查找,找到能插入的位置,这样是不是就会降为logn的时间复杂度了,事实不是这样的,当找到插入位置时,后面的元素向后移动花费的时间复杂度仍然是n

find()函数,一个指针指向头部,一个指针指向尾部,每次比较移动一个指针
时间复杂度O(n)

跟之前的比确实有所改进

2.链表

find()函数跟顺序表的时间复杂度是一样的

之前说到顺序表的add()函数,利用二分法但是插入时需要n的时间复杂度,链表的插入只需要O(1)的时间,这样是不是就会有所改进,事实也不是这样的,因为链表没法利用二分法,二分法是基于数组的下标的

我们思考,如何能提高查找插入的正确位置更快,如何插入的速度更快呢,这时我们想到了哈希表

3.哈希表

这里我们直接利用c++自带的map

find()函数
我们map<int,int>key为储存的数字的值,value为当前数值的数字的个数
我们只需要将查找的元素减去map中的每个值,查找他们的差是否存在即可
时间复杂度是O(n)吗,还没有算查找的时间,这里用的是map,所以时间复杂度为O(nlogn)

插入需要的时间O(1),查找位置需要的时间O(1)
所以这里的时间是O(1)吗
事实并不是的,我们这里虽然用的是hash_map但是事实上它并不是哈希表,它的底层是红黑树
哈希表的话添加元素当然是O(1)
红黑树的插入操作时间复杂度为O(logn)
所以这里的时间复杂度为O(logn)

代码部分

class TwoSum {
public:
	map<int,int> hash_map;
    void add(int number) {
    	
		if(hash_map.find(number)!=hash_map.end())	//存在 
		{
			hash_map[number]++;
		}
		else
		{
			hash_map.insert(make_pair(number,1));
		}
    }

    bool find(int value) {
		for(auto it=hash_map.begin();it!=hash_map.end();it++)
		{
			int num=value - it->first;
			int cnt= num==it->first?2:1;
		//	cout<<value<<" "<<num<<" "<<cnt<<endl;
			if(hash_map.find(num)!=hash_map.end())
			{
				if(hash_map[num]>=cnt)
					return true;
			}
		}
		
		return false;
    }
};

总结

顺序表
添加元素的时间复杂度为O(n),查找元素的时间复杂度为O(logn)

链表
添加元素的时间复杂度为O(1),查找元素的时间复杂度为O(n)

相比之下顺序表更适合查找元素,链表更适合添加元素

哈希表
添加元素的时间复杂度为O(1),查找元素的时间复杂度为O(1)
但是哈希表的空间复杂度很高,底层原理为散列表,当数据非常分散的时候会造成大量的空间浪费

红黑树(c++自带的map)
添加元素的时间复杂度为O(logn),查找元素的时间复杂度为O(logn)
相比之下,利用红黑树可能更全面一些
当一个元素需要查找它特定的位置并且插入的时候,红黑树是最好的选择

May you succeed

举报

相关推荐

0 条评论