1、哈希表基础知识
以键值对的方式进行数据存储 优点:哈希表数据结构在插入、删除或查找一个元素时,都只需要O(1)的时间
哈希表设计三要点:
为了快速确定一个元素在哈希表中的位置,可以使用一个数组,元素的位置为他的哈希值除于数组长度的余数。 由于多个哈希值不同的元素可能会被存入同一数组位置,数组的每个位置对应一个链表,因此存入同一位置的多个元素都被添加到同一个链表中。 为了确保链表不会太长,就需要计算哈希表中元素的数目与数组长度的比值。当这个比值超过某个阈值时,就对数组进行扩容处理,并把哈希表中的所有元素重新分配位置。
2、LCR 030. O(1) 时间插入、删除和获取随机元素
题目信息:
https://leetcode.cn/problems/FortPu/description/
设计一个支持在平均 时间复杂度 O ( 1 ) 下,执行以下操作的数据结构:insert ( val) :当元素 val 不存在时返回 true ,并向集合中插入该项,否则返回 false 。
remove ( val) :当元素 val 存在时返回 true ,并从集合中移除该项,否则返回 false 。
getRandom:随机返回现有集合中的一项。每个元素应该有 相同的概率 被返回。示例 1 :
输入: inputs = [ "RandomizedSet" , "insert" , "remove" , "insert" , "getRandom" , "remove" , "insert" , "getRandom" ]
[ [ ] , [ 1 ] , [ 2 ] , [ 2 ] , [ ] , [ 1 ] , [ 2 ] , [ ] ]
输出: [ null, true , false , true , 2 , true , false , 2 ]
解释:
RandomizedSet randomSet = new RandomizedSet ( ) ;
randomSet. insert ( 1 ) ;
randomSet. remove ( 2 ) ;
randomSet. insert ( 2 ) ;
randomSet. getRandom ( ) ;
randomSet. remove ( 1 ) ;
randomSet. insert ( 2 ) ;
randomSet. getRandom ( ) ; 提示:
- 231 <= val <= 231 - 1
最多进行 2 * 105 次 insert , remove 和 getRandom 方法调用
当调用 getRandom 方法时,集合中至少有一个元素
解题思路:
1、审题:实现时间复杂度O(1)的哈希表,包含操作插入,删除,和随机获取内部数据 2、解题:该题要实现哈希表的功能,主要要求是时间复杂度为O(1) 插入操作: 使用动态数组vector保存插入后的数据,这样可以随机访问数组内的元素 删除操作: 要实现数据的删除,需要先知道该数值在数组内的下标位置,可以使用map数据结构保存,key为数值,value为该数值在数组中的下标位置 这样就可以通过数值获取到对应保存的下标位置, 还有一个问题是数组中元素删除,需要将后面部分元素进行整体移动,时间复杂度为O(n) 要实现数组元素删除时间复杂度为O(1),可将当前需要删除的元素与数组尾部元素进行交换,然后直接删除数组尾部的元素 随机获取操作:
代码实现:
class RandomizedSet
{
public : RandomizedSet ( ) { } bool insert ( int val) { if ( arrLocationMap. find ( val) != arrLocationMap. end ( ) ) { return false ; } arrLocationMap[ val] = array. size ( ) ; array. push_back ( val) ; return true ; } bool remove ( int val) { if ( arrLocationMap. find ( val) == arrLocationMap. end ( ) ) { return false ; } int removeIndex = arrLocationMap[ val] ; int size = array. size ( ) ; int removeVal = array[ removeIndex] ; int tailVal = array[ size - 1 ] ; arrLocationMap[ tailVal] = removeIndex; array[ removeIndex] = tailVal; array[ size - 1 ] = removeVal; array. pop_back ( ) ; arrLocationMap. erase ( val) ; return true ; } int getRandom ( ) { std:: mt19937 generate ( rd ( ) ) ; std:: uniform_int_distribution< int > dist ( 0 , array. size ( ) - 1 ) ; int index = dist ( generate) ; return array[ index] ; } private : std:: vector< int > array; std:: map< int , int > arrLocationMap; std:: random_device rd;
} ;
3、总结
普通的map哈希表结构为数组与链表组合,插入与获取数据操作,需要遍历链表,时间复杂度为O(n) 要设计O(1)时间复杂度的哈希表,可使用数组进行插入与获取数据,时间复杂度为O(1),因为数组可通过下标索引操作 而数组的删除操作,可利用交换处理,转变为最终删除数组尾部元素,只是要知道删元素的位置所在,所以需要一个map值保存每个元素在数组中的下标位置。 map操作方法,find为查询元素是否存在,erase为删除元素操作。