概念
题目
输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,则输出任意一对即可。
示例 1:
输入: nums = [2,7,11,15], target = 9
输出: [2,7] 或者 [7,2]
示例 2:
输入: nums = [10,26,30,31,47,60], target = 40
输出: [10,30] 或者 [30,10]
限制:
1 <= nums.length <= 10^51 <= nums[i] <= 10^6
解题思路🙋🏻 ♀️
假设输入数组是 [2,7,11,15],目标数是 9。
初始状态,left 指向第一个元素,right 指向最后一个元素:
nums: 2 -> 7 -> 11 -> 15
^ ^
leftPointer rightPointer
第一次迭代,leftPointer 和 rightPointer 指向的元素之和是 17,大于目标数 9,所以我们将 rightPointer 向左移动一位:
nums: 2 -> 7 -> 11 -> 15
^ ^
leftPointer rightPointer
第二次迭代,leftPointer 和 rightPointer 指向的元素之和是 13,仍然大于目标数 9,所以我们再次将 rightPointer 向左移动一位:
nums: 2 -> 7 -> 11 -> 15
^ ^
leftPointer rightPointer
第三次迭代,leftPointer 和 rightPointer 指向的元素之和是 9,正好等于目标数,所以我们找到了解答:
nums: 2 -> 7 -> 11 -> 15
^ ^
leftPointer rightPointer
所以,最终的结果就是 [2,7]。
边界思考🤔
特殊处理的情况主要是当数组中存在多对和为目标数的元素时,我们只需要返回其中任意一对即可。
以下是对应的图示:
-
当数组为空时,我们无法找到解答:
nums: -
当数组只包含一个元素时,我们同样无法找到解答:
nums: 1 -
当数组中所有元素的和都小于目标数时,我们无法找到解答:
nums: 1 -> 2 -> 3 -> 4 -> 5 target: 15 -
当数组中存在多对和为目标数的元素时,我们只需要返回其中任意一对即可:
初始状态: nums: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 target: 8结果可以是 [1, 7],也可以是 [2, 6],或者 [3, 5]。
代码
class Solution {
func twoSum(_ nums: [Int], _ target: Int) -> [Int] {
// 如果数组的元素个数小于等于1,那么直接返回空数组,因为没有可能的答案
if nums.count <= 1 {
return []
}
// 初始化两个指针,left 指向数组的开始,right 指向数组的结尾
var left = 0
var right = nums.count - 1
// 当 left 指针小于 right 指针时,执行循环
while left < right {
// 如果两个指针指向的元素的和大于目标值,那么将 right 指针向左移动一位
if nums[right] + nums [left] > target {
right -= 1
// 如果两个指针指向的元素的和小于目标值,那么将 left 指针向右移动一位
} else if nums[right] + nums[left] < target {
left += 1
// 如果两个指针指向的元素的和等于目标值,那么返回这两个元素
} else {
return [nums[right], nums[left]]
}
}
// 如果循环结束都没有找到答案,那么返回空数组
return []
}
}
时空复杂度分析
时间复杂度 O (n), 通过两个指针来寻找数组中的两个数,使得这两个数的和等于目标值。因为我们只是在原数组上进行操作,没有使用额外的数组或者字符串,所以空间复杂度是 O(1)。