1.哈希表的基础概念
哈希表是一种数据结构,它使用哈希函数将键映射到存储桶或槽位中。它通过将键转换为索引来实现快速的插入、查找和删除操作。哈希表通常用于需要高效查找的场景,如字典、缓存和数据库中。
常见哈希结构
- 数组
- set(集合)
- map(映射)-py里面是dict (字典)
py中的set为无序的不可重复的key。
字典包含key和value
当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法!
看这篇博文应该就能对哈希表有个基础的了解了。来吧!一文彻底搞定哈希表!_哈希表庆哥_庆哥Java的博客-CSDN博客
2.算法实战
2.1第1题
给定一个整数数组 nums
和一个整数目标值 target
,请你在该数组中找出 和为目标值 target
的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
(1)暴力枚举法
class Solution(object):
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
left = 0
right = 0
for i in range(len(nums)):
for j in range(left+1,len(nums)):
if nums[j] + nums[left] == target:
return [left,j]
else:
j = j + 1
left = left + 1
时间很长,没想到这也能打败10%。
(2)哈希表
class Solution(object):
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
hash_table = dict()
for i, num in enumerate(nums):
if target - num in hash_table:
return [hash_table[target-num], i]
else:
hash_table[num] = i
2.2第49题
给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。
字母异位词 是由重新排列源单词的所有字母得到的一个新单词。
示例 1:
输入: strs = ["eat", "tea", "tan", "ate", "nat", "bat"]
输出: [["bat"],["nat","tan"],["ate","eat","tea"]]
示例 2:
输入: strs = [""]
输出: [[""]]
示例 3:
输入: strs = ["a"]
输出: [["a"]]
心得:该题主要是找到具有相同字母的异构单词之间的共性,提取出来作为哈希表的键,值就是具有相同字母的异构单词列表。没做出来,想到了用数字代替字母排序,但是只想到了加法,觉得不具有唯一性就没用。看了讨论区,大佬用质数的方法代替字母,这样质数的乘积是唯一的,相同字母组成的异构单词就具有相同的性质,就可以用字典来储存表示了。官方答案写的没看懂。
class Solution(object):
def groupAnagrams(self, strs):
"""
:type strs: List[str]
:rtype: List[List[str]]
"""
map = {
'a':2,'b':3,'c':5,'d':7,'e':11,'f':13,'g':17,'h':19,'i':23,'j':29,'k':31,'l':37,'m':41,
'n':43,'o':47,'p':53,'q':59,'r':61,'s':67,'t':71,'u':73,'v':79,'w':83,'x':89,'y':97,'z':101
}
resmap={}
reslist = []
for str in strs:
m = 1
for i in range(len(str)):
m*=map[str[i]]
if not m in resmap:
resmap[m]=[]
resmap[m].append(str)
# print(resmap.values())
return [j for j in resmap.values()]
2.3第128题
给定一个未排序的整数数组 nums
,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。
请你设计并实现时间复杂度为 O(n)
的算法解决此问题。
示例 1:
输入:nums = [100,4,200,1,3,2]
输出:4
解释:最长数字连续序列是 [1, 2, 3, 4]。它的长度为 4。
示例 2:
输入:nums = [0,3,7,2,5,8,4,6,0,1] 输出:9
心得:哈希表实在掌握的太差,只能用最蠢的方法暴力解出来,但是时间已经超出限制了。
class Solution(object):
def longestConsecutive(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
if len(nums)==0:
return 0
if len(nums)==1:
return 1
i = 0
j = 0
cur_len = 1
max_len = 1
for i in range(len(nums) - 1):
for j in range(len(nums) - 1 - i):
if nums[j] > nums[j+1]:
temp = nums[j+1]
nums[j+1] = nums[j]
nums[j] = temp
for k in range(len(nums) - 1):
if nums[k+1]==nums[k]:
continue
elif nums[k+1]==nums[k] + 1:
cur_len = cur_len + 1
if max_len < cur_len:
max_len = cur_len
else:
cur_len = 1
return max_len
return nums
看了一眼解析,发现使用的set(),只能说掌握的知识太少了,去看了set()的用法后自己终于写出来了一版。但是时间和内存的消耗还是很大。
class Solution(object):
def longestConsecutive(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
up = 1
down = 1
cur_len = 1
max_len = 1
if len(nums)==0:
return 0
if len(nums)==1:
return 1
hash_table = set()
for i in range(len(nums)):
hash_table.add(nums[i])
j = 0
while j < len(nums)-1:
hash_table.discard(nums[j])
if nums[j] + up in hash_table:
hash_table.remove(nums[j] + up)
up = up + 1
elif nums[j] - down in hash_table:
hash_table.remove(nums[j] - down)
down = down + 1
else:
cur_len = up + down - 1
up = 1
down = 1
if cur_len > max_len:
max_len = cur_len
j = j + 1
return max_len
发现可以hash_table=set(nums),内存减少了一些,竟然击败增加了这么多。
看了官方的答案写出来的一版。更加的简洁。
class Solution(object):
def longestConsecutive(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
cur_len = 1
max_len = 1
if len(nums)==0:
return 0
if len(nums)==1:
return 1
hash_table = set(nums)
for num in hash_table:
if num - 1 not in hash_table:
# 如果表中没有比它小1的,就开始寻找大1的,然后一直往上找
cur_num = num
cur_len = 1
# 如果比它大1存在,则开始计数
while cur_num + 1 in hash_table:
cur_num = cur_num + 1
cur_len = cur_len + 1
if max_len < cur_len:
max_len = cur_len
# 如果有比它小1的,直接不管,继续循环,直到找到没有比它小1的
return max_len
3.总结
做完哈希表的题发现有几个重点,一个是什么时候用,在需要快速查找一个元素是否在集合里时,就要用到哈希表。一个是需要掌握数组,dict(),set()的基础用法,不然真的很麻烦。
4.需要掌握的知识
4.1数组基本用法
1、Python的数组分三种类型:
(1) list 普通的链表,初始化后可以通过特定方法动态增加元素。
定义方式:arr = [元素]
文章python数组使用(超级全面)_27Up的博客-CSDN博客
- a、定义时初始化,a = [1,2,[1,2,3]],b、定义时不初始化,一维数组:arr = []
- del 删除数组里的指定元素,如: del arr[0]
- d、遍历数组:
for k, v in enumerate(arr):
print k, v - e、增加元素:一维arr.append('aaa'),二维arr[0].append('aaa')
如果要在任意位置插入用 arr.insert(n, 值) - list的方法
L.append(var) #追加元素
L.insert(index,var)
L.pop(var) #返回最后一个元素,并从list中删除之
L.remove(var) #删除第一次出现的该元素
L.count(var) #该元素在列表中出现的个数
L.index(var) #该元素的位置,无则抛异常
L.extend(list) #追加list,即合并list到L上
L.sort() #排序
L.reverse() #倒序
(2) Tuple 固定的数组,一旦定义后,其元素个数是不能再改变的。
定义方式:arr = (元素)
Tuple 没有的方法:
[1] 不能向 tuple 增加元素,没有 append 、 extend 、insert 等方法。
[2] 不能从 tuple 删除元素,没有 remove 或 pop 方法。
[3] 不能在 tuple 中查找元素,没有 index 方法(index是查找而不是索引,索引直接用下标即可,如:t[0])。
Tuple 可以转换成 list, 反之亦然。
转换方式为:t = list( t ),反之:arr = tuple( arr )
(3) Dictionary 词典类型, 即是Hash数组。
定义方式:arr = {元素k:v}
#Dictionary 的用法比较简单,它可以存储任意值,并允许是不同类型的值,下面实例来说明:
#下面例子中 a 是整数, b 是字符串, c 是数组,这个例子充分说明哈希数组的适用性。
dict_arr = {'a': 100, 'b':'boy', 'c':['o', 'p', 'q']}
#可以直接增加一个元素,如果同名,则会改变原来的key的元素的值
dict_arr['d'] = 'dog'
#输出所有的key
print dict_arr.keys()
#输出所有的value
print dict_arr.values()
4.2dict()基本用法
- 当我们不需要这个元素时,需要把元素从dict中删除,pop()方法快速删除元素。但需要指定需要删除元素的key,并返回value。<**注>**pop()方法的参数是dict中的key,当key不存在时,同样会引起错误。
- 读取dict 元素。创建一个dict ,dict 通过key找到对应的value的功能。还可以通过key来获取对应的value,dict提供get方法,把key当作参数传递给get方法。当Key不存在时也不会出错。
- 添加dict元素dict和tuple不一样,dict是可变的,我们随时可以往dict中添加新的key-value,value可以是任意类型的元素,可以是list、tuple等,如d['Alice'] =[50,61,66]赋值语句有两个功能:
1.当key不存在时,往dict中添加对应的key:value元素。
2.当key存在时,会更新dict,用新的value 替换原来的value。 - python遍历dict遍历dict有两种方法
第一种是遍历dict的所有key,并通过key获得对应的value。
第二种方法是通过dict提供的items()方法,items()方法会返回dict中所有的元素,每个元素包含key和value。for key,value in d.items(): - 清除所有元素dict 提供clear()函数,直接清除dict 中所有元素。d.clear()
4.1set()基本用法
文章Python 集合set详解(超详细)_python set集合_LeoATLiang的博客-CSDN博客
- 集合(set)是一个无序的不重复元素序列。
- 可以使用大括号 { } 或者 set() 函数创建集合,注意:创建一个空集合必须用 set() 而不是 { },因为 { } 是用来创建一个空字典。
- 我们无法通过引用索引来访问 set 中的项目,因为 set 是无序的,项目没有索引。但是可以使用 for 循环遍历 set 项目,或者使用 in 关键字查询集合中是否存在指定值。
- add() 方法用于给集合添加元素,如果添加的元素在集合中已存在,则不执行任何操作。
- update() 方法用于修改当前集合,可以添加新的元素或集合到当前集合中,如果添加的元素在集合中已存在,则该元素只会出现一次,重复的会忽略。update()可以合并两个集合。
-
remove() 方法用于移除集合中的指定元素。该方法不同于 discard() 方法,因为 remove() 方法在移除一个不存在的元素时会发生错误,而 discard() 方法不会。
-
clear() 方法用于移除集合中的所有元素。
-
删除则使用del函数。