剑指42.和为S的两个数字

题目描述

输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。
 

输出描述:

对应每个测试案例,输出两个数,小的先输出。
 

思路

             双指针。本题的关键是数组是递增排序的。那么我们可以定义两个指针,初始化第一个指针指向数组中第一个(最小的)数字,第二个指针指向数组的最后一个(最大的)数字。

  •              如果它们的和正好等于输入的S,即满足题意。
  •              否则,如果和小于S,我们希望和再大一点,由于数组是递增排序的,我们可以考虑选择较小的数字后面的数字(更大)。
  •              如果和大于S,我们选择较大数字前面的数字(更小)。

时间复杂度:只有一个while循环,由于是从两端向中间扫描数组,因此复杂度是O(n)。要优于固定一个数字再对后面数字遍历的方法(这种方法O(n^2))。

 

代码实现

import java.util.ArrayList;
public class Solution {
    // Note:题目要求输出两个数乘积最小的一对
    //不要被题目误导了!乘积最小的那一对就是最先找到的,直接返回即可。
    //例如,1,2,3,4,5,6 要求sum为7,那么最外层的1和6的乘积要 小于 内层(2*5、3*4)
    //用数学分析一波,a + b = sum,那么较小的数字a和较大的数字b满足大小关系: a < sum/2 < b  即a在对称轴左侧
    // 设x是较小的那个数,乘积x(7-x)= -x^2+7x,在对称轴左侧是单调递增的,说明x越小乘积越小。
    public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) {
        ArrayList<Integer> res = new ArrayList<>();
        if (array == null || array.length == 0)
            return res;
        int smallIndex = 0;   // 这里small和big记录的都是下标
        int bigIndex = array.length - 1;
        while (smallIndex < bigIndex){
            int tempSum = array[smallIndex] + array[bigIndex];
            if (tempSum == sum){
                    res.add(array[smallIndex]);
                    res.add(array[bigIndex]);
                    // 最外层的乘积最小
                    break;
            }else if (tempSum < sum){
                smallIndex++;
            }else{//tempSum > sum
                bigIndex--;
            }
        }
        return res;
    }
}

 

 
posted @ 2020-08-25 22:15  不学无墅_NKer  阅读(135)  评论(0编辑  收藏  举报