题目描述
输入一个递增排序的数组和一个数字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 }