题目描述
输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。
输出描述:
对应每个测试案例,输出两个数,小的先输出。
思路:
两个指针,分别从前后同时扫描数组,如果和大于 sum, 后面的数组往中间移一个,如果小于 sum, 前面的数组往中间移一位
这题主要要注意第一次碰到相加等于 sum 的两个数的乘积就是最小的,不能被题目坑了
找到的第一组(相差最大的)就是乘积最小的。
可以这样证明:https://www.nowcoder.com/questionTerminal/390da4f7a00f44bea7c2f3d19491311b?f=discussion
考虑x+y=C(C是常数),x*y的大小。
不妨设y>=x,y-x=d>=0,
即y=x+d, 2x+d=C, x=(C-d)/2,
x*y=x(x+d)=(C-d)(C+d)/4=(C^2-d^2)/4,
也就是x*y是一个关于变量d的二次函数,对称轴是y轴,开口向下。d是>=0的,d越大, x*y也就越小
1 import java.util.ArrayList;
2 public class Solution {
3 public static ArrayList<Integer> FindNumbersWithSum(int [] array, int sum) {
4 ArrayList<Integer> list = new ArrayList<Integer>();
5 if(array == null || array.length == 0){
6 return list;
7 }
8
9 // 其实第一次碰到相加等于 sum 的两个数的乘积就是最小的,不能被题目坑了
10
11 // 两个指针,分别从前后同时扫描数组
12 int i = 0, j = array.length - 1;
13 int a = 0, b = 0;
14 int mul = 1 << 30;
15 while(i < j){
16 // 如果和大于 sum, 后面的数组往中间移一个
17 int temp = array[i] + array[j];
18 if(temp == sum){
19 list.add(array[i]);
20 list.add(array[j]);
21 break;
22 }else if(temp > sum){
23 j--;
24 }else{
25 i++;
26 }
27 }
28 return list;
29 }
30 }