题目描述
小R有一个按升序排序的整数数组,他的任务是查找其中两数,使得它们的和等于给定的目标数字。如果存在多对符合条件的数字,输出找到的第一对数字。若无符合条件的组合,则返回结果异常。每次返回的结果包括是否找到结果的状态及该两数的索引和它们的值。
例如:在输入的数组 [1, 2, 4, 7, 11, 15] 中,找到的第一对和为 6 的数字是 2 和 4。
返回一个列表 [1,2,4]
题目解析
在这个题目中我们要注意的点有四个:
- 升序排序,意味着数据都是从小到大排列的
- 其中两数和等于给定目标值
- 返回找到的第一对数字 --> 按照每对符合结果的数字中的第一个数字的索引来算,比如示例中第一对数字和为6的数字是2和4,数字2的索引为1,数字4的索引为2,如果后续有索引为4,5的数字也符合,也只返回这一对数字,因为其中索引最小
- 返回结果为两部分 --> 是否找到(用0和1来表示,1表示找到,0表示未找到)、数值
根据条件1和2,由于数组是升序排序的,数组由小到大排序,而且要在数组中寻找和为目标值target的数,我们可以使用双指针法来解决这个问题,定义一左一右两个指针
左指针left初始指向索引为0的数字,右指针right初始指向索引为n-1的数字(n为给定数组长度),然后根据移动条件,左指针从左到右移动,右指针从右到左移动。
那么,移动的条件是什么呢?就是根据我们的条件2而来确定左右指针的移动问题,因为题目要求两数和等于给定目标值,这个和s就是左指针left指向的值加上右指针right指向的值,s = arr[left] + arr[right]
-
如果这个s小于目标值target,由于数组是升序排序的,那么就说明left指向的值
arr[left]太小,不符合我们条件2的要求,那么我们移动左指针left,向右移动,放大left指向的值if s < target : left+=1 -
如果这个s大于目标值target,由于数组是升序排序的,那么就说明Ritht指向的值
arr[right]太大,不符合我们条件2的要求,那么我们移动右指针left,向左移动,缩小Ritht指向的值if s > target : right-=1 -
如果s等于目标值target,那么我们直接返回数组(我们使用双指针的时候left一直指向符合条件3的最左边的值,所以可以直接返回),根据条件4,第0个位置为1(表示找到了),第1个位置为
arr[left],第二个位置为arr[right] -
如果没找到(也就是当循环结束的时候,仍然没有找到和为target的两个数),那么直接返回[0,0,0],表示没有找到结果
代码解析
- 定义变量,n为输入数组arr的长度,定义左右指针,答案ans数组初始化直接为
[0,0,0],后续如果满足条件则直接赋值,若未满足条件则直接返回这个ans。
def solution(arr: list, target: int) -> list:
n = len(arr)
ans=[0]*3
right,left = n-1,0
-
主循环,当左指针的值小于右指针的时候,意味着没有遍历完,然后下面的逻辑就是上面所说的三种情况,s大于target,s小于target以及s等于target的时候的处理
while left < right:
if arr[left]+arr[right] > target:
right-=1
elif arr[left]+arr[right] < target:
left +=1
else:
if ans[0] != 1 : ans[0] =1
ans[1]=arr[left]
ans[2]=arr[right]
break
return ans
完整代码
def solution(arr: list, target: int) -> list:
# write code here
n = len(arr)
ans=[0]*3
right,left = n-1,0
while left < right:
if arr[left]+arr[right] > target:
right-=1
elif arr[left]+arr[right] < target:
left +=1
else:
if ans[0] != 1 : ans[0] =1
ans[1]=arr[left]
ans[2]=arr[right]
break
print("ans:",ans)
return ans