[菜鸟训练]剑指 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

来源:力扣(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);
        }
    }
}

猜你喜欢

转载自blog.csdn.net/Puppet__/article/details/115127782