LeetCode高频100题刷题记录之——两数求和
终于开始刷LeetCode了,还没有系统学习过数据结构,导致第一题做出来就很垃圾,只会使用暴力求解,还使用了巨多判断来试图简化计算过程,结果是计算量没有省不说,还严重增加了调试成本。
但是毕竟刚开始,接受自己是个菜鸡的事实也不丢人嘿嘿,因此记录一下用python实现两数求和的过程,包括暴力破解和哈希表查找法,不得不说,哈希表在处理这种问题时真的很有优势,刚刚接触哈希表,后续再不断学习吧!
1 暴力破解法
1.1 思路
做题的时候看到要求尽可能复杂度小于 O ( N 2 ) O(N^2) O(N2),但是暴力破解基本上不可能实现,只能尽可能想办法降低到侠义的 O ( N 2 ) O(N^2) O(N2)以下,其实算法复杂度从大 O O O计算法来说还是 O ( N 2 ) O(N^2) O(N2)。
输入:nums: List[int], target: int
输出:result: List[int],预定义result为None
具体思路是:
Step1:判断target是正还是非正;
Step2:构建六个空list,分别存储nums中等于0,等于target,等于target/2,以及根据正负号判断其在不同区间内的nums的索引;
Step3:判断target是否为0,若是,进一步判断nums中为0的数是否有两个,若有,则输出前两个作为result,结束程序;若无,转Step4;
Step4:判断是否存在nums中有为0与target的数,若存在,输出这两种情况各自的第一个数的索引作为result,结束程序;若无,转Step5;
Step5:判断nums中是否存在有两个以上数值为target/2的数,若存在,则输出符合条件的前两个数的索引为result,结束程序;若不存在,则转Step6;
Step6:判断nums中处于①(0, target/2)与②(target/2, target)(target为正)或处于①(target, target/2)与②(target/2, 0)(target为负)的数的存在情况,若①②都存在,遍历两组的数据,若能找到①+②=target的数,取出对应索引,作为result的值,结束程序;若①或②不存在,或者不满足①+②=target,转Step7;
Step7:判断nums中处于①(target, +∞)与②(-∞, 0)(target为正)或处于①(-∞, target)与②(0, +∞)(target为负)的数的存在情况,若①②都存在,遍历两组的数据,若能找到①+②=target的数,取出对应索引,作为result的值,若①或②不存在,或者不满足①+②=target,报错,结束程序。
1.2 Python代码
代码可在Leetcode中直接运行。
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
result = None
neg_idx = [] # 存储nums中数值小于0(target为正)或小于target(target为负)的数
pos_idx = [] # 存储nums中大于target(target为正)或大于0(target为负)的数
small_idx = [] # 储存nums中大于0但小于target/2的数
large_idx = [] # 存储nums中大于target/2但小于target的数
zero_idx = [] # 存储nums中为0的数
half_idx = [] # 存储nums中为target/2的数
equal_idx = [] # 存储nums中为target的数
if target > 0: # target为正的情况
for i in range(len(nums)):
if nums[i] == 0:
zero_idx.append(i)
elif nums[i] == target:
equal_idx.append(i)
elif nums[i] == target/2:
half_idx.append(i)
elif nums[i] < 0:
neg_idx.append(i)
elif nums[i] < target/2:
small_idx.append(i)
elif nums[i] < target:
large_idx.append(i)
else:
pos_idx.append(i)
else: # target <=0的情况
for j in range(len(nums)):
if nums[j] == 0:
zero_idx.append(j)
elif nums[j] == target:
equal_idx.append(j)
elif nums[j] == target/2:
half_idx.append(j)
elif nums[j] > 0:
pos_idx.append(j)
elif nums[j] > target/2:
large_idx.append(j)
elif nums[j] > target:
small_idx.append(j)
else:
neg_idx.append(j)
if (target == 0) & (len(zero_idx) >= 2):
result = [zero_idx[0], zero_idx[1]]
return result
elif (len(zero_idx) > 0) & (len(equal_idx) > 0): # 判断是不是有简单结果1存在
result = [zero_idx[0], equal_idx[0]]
return result
elif len(half_idx) >= 2:
result = [half_idx[0], half_idx[1]]
return result
elif (len(neg_idx) > 0) & (len(pos_idx) > 0):
for sub_i in neg_idx:
if result is not None:
break
for sub_j in pos_idx:
if nums[sub_i] + nums[sub_j] == target:
result = [sub_i, sub_j]
break
if result is not None:
return result
if result is None:
if (len(small_idx) > 0) & (len(large_idx) > 0):
for sub_i in small_idx:
if result is not None:
break
for sub_j in large_idx:
if nums[sub_i] + nums[sub_j] == target:
result = [sub_i, sub_j]
break
if result is not None:
return result
else:
raise ValueError("数组中没有和为target的两个数!")
else:
raise ValueError("数组中没有和为target的两个数!")
1.3 算法评价
判断过程过多,容易出错,过于冗余,虽然理论上可以减少一点计算量,但计算值过多时性能优势不明显。时间复杂度为 O ( N 2 ) O(N^2) O(N2)。
2 哈希表实现
2.1 思路分析
计算target与nums的差,再以差为key创建字典,判断时进行索引,方法较为简单,不做算法说明了。
2.2 代码
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
result = None
len_nums = range(len(nums))
keys = [target - nums[i] for i in len_nums] # 散列函数构造,以target与nums中每个数的差作为key
nums_dict = dict(zip(keys, len_nums)) # 根据key与值建立对应的哈希表,在python中是字典
for i in len_nums:
if nums[i] in nums_dict.keys():
if i != nums_dict[nums[i]]:
result = [nums_dict[nums[i]], i]
return result
break
if result is None:
raise ValueError("nums中没有符合条件的两个数!")
对比官方题解,发现我的代码真的太繁琐了,官方的代码非常整洁,真的强。
下面是官方题解,思路值得学习。
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
hashtable = dict()
for i, num in enumerate(nums):
if target - num in hashtable:
return [hashtable[target - num], i]
hashtable[nums[i]] = i
return []
# 作者:LeetCode-Solution
# 链接:https://leetcode-cn.com/problems/two-sum/solution/liang-shu-zhi-he-by-leetcode-solution/
# 来源:力扣(LeetCode)
# 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。