剑指offer——和为S的两个数
题目描述
输入一个递增排序的数组和一个数字S,在数组中查找两个数,是的他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。
输出描述:
对应每个测试案例,输出两个数,小的先输出。
我的解答
import java.util.ArrayList;
public class Solution {
/*常规做法:先求符合两个数之和等于sum的两个数,并且把较小的数存到result数组中;
* 遍历result数组,找乘积较小的两个数,并将该数输出到resultFinal中,输出。
*/
public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) {
ArrayList<Integer> result=new ArrayList<Integer>();
ArrayList<Integer> resultFinal=new ArrayList<Integer>();
if(sum<3 || array.length<2){
return resultFinal;
}
//第一步:符合两个数之和等于sum的两个数,并且把较小的数存到result数组中;
for(int i=0;i<array.length-1;i++){
int temp=array[i];
for(int j=i+1;j<array.length;j++){
if(temp>sum){
break;
}
if(temp+array[j]==sum){
result.add(temp);
}
}
}
int r=0;
if(result.size()!=0){
int small=result.get(0)*(sum-result.get(0));
for(int k=0;k<result.size();k++){
if(small>result.get(k)*(sum-result.get(k))){
small=result.get(k)*(sum-result.get(k));
r=k;
}
}
resultFinal.add(result.get(r));
resultFinal.add(sum-result.get(r));
}
return resultFinal;
}
}
提升
利用数学知识:按第一数从小到大的排序,第一组的乘积一定最小
通常的想法是先找到满足条件的数组对,然后比较他们的乘积取乘积最小的一组,所以数组必须要遍历完,可是我们通过数学公式推导,发现按第一数从小到大的排序,第一组的乘积一定最小,所以我们只需要从数组两端来查找满足条件的两个数,即为题目要找的数对。
结论证明:
假设:找到两组满足条件的数组对(x,y)、(x+a,y-a),其中(x+y=S, 0 < a < y - x)
x*y-[(x+a)(y-a)]
=x*y-x*y-(y-x)a+a2
=a[a-(y-x)]
因为0 < a < y-x,
所以a-(y-x)<0,
所以a[a-(y-x)]<0
因此(x,y)乘积一定比(x+a,y-a)小
相关算法很简单,可以自行写出。
仔细学习:4 ArrayList中的API