两数之和
涉及数据结构与算法概述
哈希表
- 概述:是一种数据结构(存储数据的一种方式),即哈希表是键值对映射存储,对应python中的字典
- 特点
- 存储逻辑:通过哈希函数把键转换成一个“存储位置”,比如把key=2映射到内存中的某个位置(flask源码中也是这种思想local类中内部维护一个字典)
- 查找逻辑:查某个key时通过哈希函数算出它的存储位置,一步取出对应的值,即查找时间 O(1)
哈希表法
- 概述:用哈希表这种数据结构来解决问题的方法
- 特点:优化操作效率,通过键快速查找,无需按照顺序遍历查找
总结
数据结构是工具,算法是用工具解决问题的步骤,即哈希表法是用哈希表这个工具去解决问题
题目汇总
两数之和
描述:给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
原先思路与解法的问题刨析
思路:采用正向思维,一直想着在列表里面找出这2个数,重点是侧重于找这2个数
解法:
def twoSum(nums, target: int):
n = (target + 1) / 2
new_nums = sorted(nums)
data = None
for i in range(len(new_nums)):
if new_nums[i] >= n:
data = i
break
for x in range(len(new_nums[:data])):
for y in range(len(new_nums[data:])):
if new_nums[x] + new_nums[data + y] == target:
print([x, data + y])
return None
问题刨析:
-
思路方向问题:想着目标值一定是一个比他中值小的数和一个比大的数相加而得到,然后就想把这个列表排一下序,然后分为2部分一个成员都是比中值小的数组,另外一个成员都是比他大的数组,此过程对应代码中第一个for循环那块。然后循环其中一个数组并嵌套循环第二个数组来凑和为目标值的两个数此过程对应第二个for循环。一直想着在列表里面找出这2个数,重点是侧重于找这2个数
-
代码实现问题:
-
知识点遗失:for循环初次写错了,没有加range()
-
编写过程考虑不周全:没有考虑到我是把列表重新排序了得到的是一个新列表,即使找到了也是返回的新列表中的对应下标而不是指定列表中对应值的下标,而且也没有想到办法怎么通过值找到原来列表中其对应下标。并且最初写的还是这个
if new_nums[x] + new_nums[y] == target: print([x,y])甚至都不是新列表中的下标,而是分开部分列表的下标
-
效率问题:可见我是在遍历查找而且还有嵌套遍历,所以时间复杂度是O(n^2)
-
优化思路与解法刨析
思路:
-
采用逆向思维,你不是要找值1+值2=target吗,而且target已经有了,何必一次性去找这两个数?为什么不能就只找一个数 呢?而且这两个数都在列表中,所以现在目标不再侧重于硬找两个数,而是只找一个数这个数就是补数
-
怎么才能实现只找一个数?首先明确这个题目问题!是找,找的话哈希表法是不是快?他给的是数组那我怎么和哈希表联系起来?所以思考我怎么把这个数组所有成员都搞到哈希表里面去那就是遍历整个数组,!重点:我既然是要找值,我遍历时把他放到字典中去
是不是可以把值作为key,然后我把索引作为value。因为哈希表查找是通过指定一个键利用哈希算法得到存储地址然后去去对应对的值,而且因为解题目标是找到补数,是一个数必然优先是找数,所以优先把数作为key。
-
问题来了,我之前老解法中就有疑惑没有想到办法怎么通过值找到列表中其对应下标。利用内置函数enumerate()来破解:
enumerate() 函数用于将一个可遍历的数据对象,组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。
seasons = ['Spring', 'Summer', 'Fall', 'Winter']
list(enumerate(seasons, start=1)) # 下标从 1 开始
[(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')]
- 通过值已经找到了对应下标,那问题在于怎么找了,目前解法思路重点在于找补数,补数是怎么得到?Complement=target-值1
也就是说目标值减去值一,我怎么给定这个值一呢?上面把列表与字典联系起来时遍历了列表我能不能把这个遍历时的值作为值一?
边放入字典时边再里面找?因为你不可能一下子全放入字典,且值一是变化的,即使为这个数时字典中还没有这个数的相应想的补
数,但凡这个补数你在列表中我值一在遍历时是不是一定会遍历到你!即使第一次错过了后面遍历到补数时,相对而言,前面要的那
个数是不是才是补数?即使你这两个数在最后,我是不是遍历完还是可以找到,而且时间复杂度是O(n),因为只遍历了列表O(n),而 再字典中找时为O(1)
解法:
def twoSum(nums, target: int):
new_nums = enumerate(nums)
nums_map = {}
for index,value in new_nums:
complement = target - value
if complement in nums_map:
return [nums_map[complement],index]
nums_map[value] = index
return None
总结
相较于原解法,优化解法在思路上改变:利用空间优化时间改善查找效率,即搞一个字典来放列表中值和索引,而且用逆向思维去解决找一个数的补数,不再正向思维硬生生找两个数
浙公网安备 33010602011771号