剑指 Offer 57. 和为s的两个数字
输入一个递增排序的数组和一个数字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^5
1 <= nums[i] <= 10^6
解法一:哈希表
遍历数组,判断target - nums[i]
是否已经Set
中存在
1. 存在,找到了一对结果[target - nums[i],nums[i]]
,直接返回这对结果
2. 不存在,将当前值nums[i]
加入Set
,继续往后遍历
3. 数组遍历结束都没有返回结果,结果不存在,返回new int[]{-1,-1};
Java代码
class Solution {
public int[] twoSum(int[] nums, int target) {
if(nums == null || nums.length < 2) return new int[]{-1,-1};
Set<Integer> set = new HashSet<>();
for(int i = 0;i < nums.length;i++){
if(set.contains(target - nums[i])){
return new int[]{target - nums[i],nums[i]};
}else{
set.add(nums[i]);
}
}
return new int[]{-1,-1};
}
}
解法二:双指针
题目已经告知数组是递增
的,所以我们可以用两个指针l
和r
不断往中间扫描
1. 当两个指针所指的值之和小于target
时,l
往右移动
2. 当两个指针所指的值之和大于target
时,r
往左移动
3. 当两个指针所指的值之和等于target
时,找到了一对结果,直接返回这对结果
4. l > r
时会退出循环,此时说明循环内部没有返回结果,那就是没有找到结果,返回new int[]{-1,-1};
时间复杂度: 只遍历了一次数组$O(n)$
空间复杂度: $O(1)$
Java代码
class Solution {
public int[] twoSum(int[] nums, int target) {
if(nums == null || nums.length < 2) return new int[]{-1,-1};
int l = 0,r = nums.length - 1;
while(l < r){
if(nums[l] + nums[r] < target){
l++;
}else if(nums[l] + nums[r] > target){
r--;
}else{
return new int[]{nums[l],nums[r]};
}
}
return new int[]{-1,-1};
}
}
第二个方法我觉得应该加排序,乱序可能不能用二分,感觉