@ author = YHR | 原创不易,转载请注明来源!
文章目录
题目描述
给出一个整数数组,请在数组中找出两个加起来等于目标值的数
给出的函数twoSum 需要返回这两个数字的下标(index1,index2),需要满足 index1 小于index2。注意:下标是从1开始的。
假设给出的数组中只存在唯一解,例如: 给出的数组为 {20, 70, 110, 150},目标值为90,输出 index1=1, index2=2
2021/1/26 马一下
明天写了 要搬家啦!
2021/1/27
讲讲我的两个方法把,方法2是方法1的精进版本哦~
方法一: 遍历两次原数组,全部建立完hash table, key=number, value=[index(s)],再开始处理
思路 1 讲解:
- 一、第一遍,遍历原数组,生成 完整的 hash table: 示例如下图
- hash table 初始为空,分为key 与 value, 开始遍历 data 数组
- 遍历 data 数组,index=0,数字为20, 此时hash Table的 key 里没有 “20” 这个键,于是把他插入hash table --> key=20, value列为列表形式! 插入index = 0
- 遍历 data 数组,index=1,数字为30, 此时hash Table的 key 里没有 “30” 这个键,于是把key=30, 插入index = 1 (value列为列表形式!)
- 遍历 data 数组,index=2,数字为20, 此时hash Table的 key 里已经有 “20” 这个键,也就是发生了 碰撞 (collision) ,于是只需要把当前的 index=2 新添入 key=20对应的value列表 中。
- 二、第二次,遍历原数组,对 target - 当前数 = remainder ,即当前数的 补, 进行判断。
remainder = target - numbers[_]
情况1 : remainder == 当前数number[_] , 即值相同
那么只需判定 remainder 是否是 numbers[ _ ]自己:
若 remainder 是numbers[_]自己,则跳过;
如果remainder是本数组里另外一个和numbers[ _ ]值相同的数则通过,即 remainder 不是 numbers[ _ ] 自己, 且此时 remainder的 index 一定在numbers[ _ ] 的index 的后面!
具体如何判断呢? 刚才 第一步建立好的, 完整的 hashTable 这不就帮上忙了!
hash table 里面的 value是一个列表,当不同index的数如果值相同时,
也即发生碰撞的话,就把对应的index都存进 key 对应的 value 来。
- 此时,如果 remainder == 当前数numbers[ _ ] , 假设他俩值是 key_i, 那么在 hash table 里:
- 如果 key_i 对应的value 这个列表,长度只有1 (只有一个数), 那么 remainder就是 numbers[ _ ] 本身,跳过!
- 但如果 key_i 对应的value 这个列表,长度>=2 (至少2个数), 即 remainder 不是 numbers[ _ ] 自己, 那么 remainder就是 value里_的后一个数字, 也就是: numbers[ _ ]的下标 _ 在 value下标为 value.index( _ ), 那么 remainder的下标就是 value[value.index( _ )+1]
if remainder == numbers[_]:
value_list = hashMap[remainder]
if len(value_list) == 1:
'''remainder 是numbers[_]自己, 不成立, 跳过'''
pass
else:
remainder_index = value_list[value_list.index(_) + 1]
'''remainder是 numbers[_]后面的 数 '''
''' +1 是因为 返回的index 要求从1开始'''
return [_ + 1, remainder_index + 1]
例子:
- target = 40, 当前数=20,index=0
- remainder= 40 - 20= 20 --> remainder == 当前数numbers[ _ ]
- 查看hash Table 里 key =20 对应的value的长度,发现 len(value) = 2 > 1,说明有俩数,那么remainder的index就是 value_list[value_list.index(0) = 2,最后返回 [0+1, 2+1]
情况2 : remainder != 当前数number[_] and remainder in hashMap, 值不同 但在 hashMapL可以找到remainder
此时说明直接找到了数组里,当前数的补数啦~
elif remainder != numbers[_] and remainder in hashMap:
# remainder 在hashMap里
value_list = hashMap[remainder] # a list of remain index
''' +1 是因为 返回的index 要求从1开始'''
return [_ + 1, value_list[0] + 1]
例子:
- target = 50, 当前数=20,index=0
- remainder= 50 - 20= 30 --> remainder != 当前数numbers[ _ ] ,且 remainder 在hash Map里。
- 直接得到 remainder 的index = hashMap[30] [0]= 1
- 返回 [0+1, 1+1]
情况3 : remainder != 当前数number[_] and remainder not in hashMap, 值不同 , hashMapL也找不到remainder
此时说明:当前数组里 **不存在** 当前数的补数, 开始遍历下一个数~
思路一代码
异常情况处理:至少保证数组里有两个数
class Solution:
def twoSum(self, numbers, target):
# write code here
if len(numbers) > 1:
return self.getHash(numbers, target)
else:
return []
pass
处理代码:
def getHash(self, numbers, target):
hashMap = {}
for _ in range(len(numbers)):
if numbers[_] in hashMap:
hashMap[numbers[_]].append(_)
else:
hashMap[numbers[_]] = [_]
for _ in range(len(numbers)):
remainder = target - numbers[_]
if remainder == numbers[_]:
value_list = hashMap[remainder]
if len(value_list) == 1:
'''remainder 是numbers[_]自己, 不成立, 跳过'''
pass
else:
remainder_index = value_list[value_list.index(_) + 1]
'''remainder是 numbers[_]后面的 数 '''
return [_ + 1, remainder_index + 1]
elif remainder != numbers[_] and remainder in hashMap:
# remainder 在hashMap里
value_list = hashMap[remainder] # a list of remain index
return [_ + 1, value_list[0] + 1]
return []
更高效的方法二: 遍历1次原数组,边建立hashMap,边查找~
刚才的方法是1. 需要遍历两遍原数组,然后 2.全部建立hashMap以后,才开始 3. 查找。
谁说,一定要全部建立好hashMap以后才能开始查找呢?
废话不多说,先放代码!
思路二代码
大家可以观察一下,以下的代码,为啥这么快就搞定咯!
异常情况处理:至少保证数组里有两个数
class Solution:
def twoSum(self, numbers, target):
# write code here
if len(numbers) > 1:
return self.getHash_traverseOnce(numbers, target)
else:
return []
pass
正式代码
def getHash_traverseOnce(self, numbers, target):
hashMap = {}
for _ in range(len(numbers)):
remainder = target - numbers[_]
if remainder in hashMap:
'''+1 是因为返回的index 要求从1开始'''
return [hashMap[remainder]+1, _+1]
else:
hashMap[numbers[_]] = _
return []
思路 2 讲解:
这个思路有俩好处:
1. 只需遍历一次原数组
2. 没必要等到 建立完整的hashMap再查找,我们可以边查边找,找到了就不继续建立咯!
思路2最大的不同,就是:
- 我们每次 插入一个新的数 进入hashMap, 我们在插入之前,就看看他的补数是不是已经在数组里了?
- 如果在的话,直接返回结果。
- 如果不在的话,就正常插入,毕竟,咱们不能排除这个数可能是,后来还没插入数的补数的可能性。
- 此外,不同于思路1, 思路2 的value 不需要是列表,仅仅存一个数值就可以啦!
图解, target=40 为例!
初始化:
-
准备插入 key= 20 & index=0, remainder = 40 - 20 = 20,而 20此时并不在hash map里,正常插入 key=20, index = 0
不同于思路1, 思路2 的value 不需要是列表,仅仅存一个数值就可以啦!
2. 准备插入 key= 30 & index=1, remainder = 40 - 30 =10, 10 并不在hash map里,正常插入 key=10, index =1
3. 准备插入 key= 20 & index=2, remainder = 40 - 20 =20, 而 20此时已经有一个存在在hash map里,说明找到了 remainder = 20, index=0!
那现在就停止插入key= 20 & index=2,因为已经找到啦他的补数 remainder = 20, index=0 啦~ 可以返回啦
return [ remainder的index=0+1, 当前数的index=2+1]
(+1 是因为要求返回的index 从1开始)