题目:输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,输出任意一对即可。
例如:输入数组{1,2,4,7,11,15}和数字15.由于4+11=15,一次输出4和11.
思路:
(1) 如果按照开始直观的想法就是从头一个个的遍历,先从1开始,然后用15-1得到14后去后面比对,如果没有继续从第二个数2开始,用15-2=13再到2后面的数里找,依次类推。这种算法的时间复杂度就是O(n的平方)。
(2) 直观的方法复杂度很高,是不是可以有其他优化的方法。那么下面说下另一种思路,可以像快速排序那样,从两头找。此方法复杂度为O(n)
例如上面的例子,从两头找,在初始位置设置标志位i=0(从第一个位置开始),在后端设置标志位j=a.length-1(数组最后一个元素位置)。然后计算两个标志位上的和sum(在这里记为sum),如果sum正好等于输入的数字s,那么这两个标志位上的元素就是和为s的一对数字。如果sum小于s,那么说明第一个标志位可以向后移动一位,从而增大两个标志位上的和。同样,如果sum大于s,第二个标志位可以向前移动一位,从而减小sum的值。按照此规律依次查找,如果在条件i<j(第一个标志位要小于第二个标志位的值)之前查找到直接返回,如果直到此条件结束没找到,那数组中不存在这样的两个数,其和为s。
代码:
import java.util.Arrays;
public class FindNumberWithSum {
public boolean FindNumber(int[] a, int sum,int[] result) {
boolean found=false;
int start = 0;// 记录数组前端
int end = a.length - 1;// 记录数组后端
while (start < end) {
if (a[start] + a[end] == sum) {
result[0] = a[start];
result[1] = a[end];
found=true;
break;
} else if (a[start] + a[end] < sum) {
start++;
} else {
end--;
}
}
return found;
}
public static void main(String[] args) {
int a[] = { -1,2, 3, 5, 8, 11,12, 13, 21, 32, 36 };
int sum = 12;
int[] result=new int[2];
FindNumberWithSum object = new FindNumberWithSum();
boolean exist = object.FindNumber(a, sum,result);
if(exist)
System.out.println(Arrays.toString(result));
else
System.out.println("不存在和为 " +sum+"的两个数");
}
}
输出结果:
[-1, 13]