剑指offer42
和为s的两个数字
题目描述
输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。
输入
[1,2,4,7,11,15],15
输出
[4,11]
思路
不要被题目误导了!证明如下,清晰明了:
//输出两个数的乘积最小的。这句话的理解?
假设:若b>a,且存在,
a + b = s;
(a - m ) + (b + m) = s
则:(a - m )(b + m)=ab - (b-a)m - m*m < ab;说明外层的乘积更小
也就是说依然是左右夹逼法!!!只需要2个指针
1.left开头,right指向结尾
2.如果和小于sum,说明太小了,left右移寻找更大的数
3.如果和大于sum,说明太大了,right左移寻找更小的数
4.和相等,把left和right的数返回
代码
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) {
ArrayList<Integer> res = new ArrayList<>();
if (array == null || array.length < 2) {
return res;
}
int minMul = 0;
int i=0;
int j = array.length-1;
while(i<j){
int temp = array[i]+array[j];
if(temp==sum){
res.add(array[i]);
res.add(array[j]);
return res;
}else if(temp<sum){
i++;
}else{
j--;
}
}
return res;
}
}
总结
很多题目都是给定一个数组,要求返回两个下标的(比如找两个元素,或者找一个子数组)。相应比较高效的解法,则是先排序,然后在一个循环体里利用两个变量进行反向的遍历,并且这两个变量遍历的方向是不变的,从而保证算法时间复杂度为 O(N)。这样类似的问题,可以考虑用双下标进行遍历。