题目描述:
输入一个递增排序的数组和一个数字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
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/he-wei-sde-liang-ge-shu-zi-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路:
方法一: 二分查找。通过题目所给的限制,明显能得出该题目不能采取直接暴力,也不能使用ArrayList来做,会很明显的时间超限。所以,我们在已知一个数查找另一个数的时候,需要采取一些方法来降低时间成本。因为所给数组有序,所以二分就是一个很好的方法。二分的具体过程不予描述。
方法二: 双指针。因为所给数组有序,我们可以采用两个指针,一个指针指向数组的最前端,即指向nums[0],一个指针指向数组的最后端,即指向nums[nums.length - 1]。
这样,假设这两个指针分别是i,j,我们得到了数组中的两个数,当前存在三种情况:
(1)nums[i] + nums[j] == target时,这说明我们找到了题目要求的一种情况,则可以结束循环。
(2)nums[i] + nums[j] > target时,这说明j所指的数过大,不妨让j左移一位,继续比较。
(3)nums[i] + nums[j] < target时,这说明i所指的数过小,不妨让i右移一位,继续比较。
为什么可以这样做,因为数组是有序的,若i不变,j所指的数和i所指的数相加大于target,那j右端的数与nums[i]相加一定会比target更大。若j不变,i所指的数和j所指的数相加小于target,那i左端的数与nums[j]相加一定会比target更大。
注意:二分时间复杂度要远高于双指针。
二分查找法时间复杂度:O(nlogn)
双指针法时间复杂度:O(n)
详细代码:
public class jianzhi_Offer_57 {
public int[] twoSum(int[] nums, int target) {
int[] ans = new int[2];
int k = 0;
for (int i = 0; i < nums.length; i++){
if(search(nums, i, nums.length-1,target-nums[i]) == true) {
//此处的写法也可和方法二一样
ans[k++] = nums[i];
ans[k++] = target - nums[i];
return ans;
}
}
return ans;
}
//二分查找
public boolean search(int[] nums, int l, int r,int target){
boolean flag = false;
if(l > r)
return flag;
int mid = (l + r) / 2;
if (nums[mid] == target){
flag = true;
}
else if(nums[mid] > target){
flag = search(nums,l,mid - 1,target);
}
else{
flag = search(nums,mid + 1, r,target);
}
return flag;
}
//双指针,一个指针指向数组的前部,一个指针指向数组的后部
//当两个指针所在的数的和比target大时,后指针左移
//当两个指针所在的数的和比target小时,前指针右移
public int[] twoSum1(int[] nums, int target) {
int i = 0, j = nums.length - 1;
while (i < j){
if(nums[i] + nums[j] == target){
int[] ans = new int[]{
nums[i],nums[j]};
return ans;
}
else if((nums[i] + nums[j]) > target){
j--;
}else
{
i++;
}
}
return null;
}
public static void main(String[] args) {
jianzhi_Offer_57 obj = new jianzhi_Offer_57();
int[] nums = new int[]{
15,31,40,43,55,55,56,56,82,98};
int[] ans = obj.twoSum1(nums, 111);
for (int i: ans
) {
System.out.println(i);
}
}
}