灵神基础算法精讲-01-学习笔记
167. 两树之和 Ⅱ - 输入有序数组
给你一个下标从1
开始的整数数组numbers
,该数组已按非递减顺序排列,请你从数组中找出满足相加之和等于目标数target
的两个数。如果设这两个数分别是numbers[index1]
和numbers[index2]
,则1 <= index1 < index2 <=numbers.length
。
暴力做法
枚举第一个数(一个for
循环),然后在后面枚举第二个数(一个for
循环)。for
循环嵌套for
循环,时间复杂度为O(n^2)
。
暴力做法没有利用到数组已经排序这个性质。
思路
首先选最小的数和最大的数相加,若相加大于target
,则他俩之间的所有数和最大的数相加肯定也大于target
,直接把最大的数去掉,从剩下的数中寻找答案;若相加小于target
,则他俩之间的所有数和最小的数相加肯定也小于target
,直接把最小的数去掉,从剩下的数中寻找答案,以此类推。
暴力做法是找两个数加起来和target
进行比较,花费O(1)
的时间就只知道了O(1)
的信息。
优化后的做法是把当前剩下的最小的数和最大的数加起来和target
进行比较,比完之后就知道其中一个数和其它任何一个数相加都是小于或大于target
的,花费O(1)
的时间知道O(n)
的信息。
优化的前提是数组是排好序的,如果数组是没有排好序的,那么就不能使用这个算法。
做法
初始化两个指针left
和right
,分别是0
和n-1
,如果这两个指针指向的数字之和恰好等于target
,则返回这两个下标;如果大于target
,就去掉最大的数,把右指针向左移动;如果小于target
,就去掉最小的数,把左指针向右移动。
1 |
|
15. 三数之和
给你一个整数数组 nums
,判断是否存在三元组 [nums[i], nums[j], nums[k]]
满足 i != j
、i != k
且 j != k
,同时还满足 nums[i] + nums[j] + nums[k] == 0
。请你返回所有和为 0
且不重复的三元组。
注意:答案中不可以包含重复的三元组。
思路
先排序,然后利用相向双指针,问题转换成剩下的两个数相加等于-nums[i]
,如果当前枚举的这个数和上一个数是相同的,直接跳过这个数。
做法
枚举第一个数i
,从0
枚举到n-3
,留两个余量。
如果第一个数的下标大于0
且该数等于上一个数就continue
,因为不能有重复的三元组。
初始化第二个数和第三个数j
、k
,接while
循环,条件为j < k
。
while
循环内首先求三数之和,如果大于0,k -= 1
;如果小于0,j += 1
,否则找到答案,ans.append
存储答案,还要在这里将重复的j
和k
也跳过: j += 1
, nums[j] == nums[j-1]
, continue
; k -= 1
, nums[k] == nums[k+1]
, continue
。
优化
如果当前i
对应的x
和其它最小的两个数之和都大于0
,则break
,后续没有机会等于0
。
如果当前i
对应的x
和其它最大的两个数之和都小于0
,则continue
,后续还有机会等于0
。
1 |
|