题目:输入一个递增排序的数组和一个数字S,在数组中查找两个数,是的他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。
如输入数组: 1,2,4,7,11,13,15
要查找S:15
则应该输出(2,13),而不是(4,11)
方法一:两次循环,遍历法,时间复杂度O(n^2)
function search2nums1($arr,$s) {
$len = count($arr);
if($s < $arr[0] || $s > $arr[$len-1]) {
return -1;
}
$product = $arr[$len-1] * $arr[$len-1];
$result = array();
for($i = 0; $i < $len; $i++) {
for($j = $i+1; $j < $len; $j++) {
$sum = $arr[$i] + $arr[$j];
if($sum == $s && $i*$j < $product ) {
$product = $i * $j;
$result = array("i"=>$arr[$i],"j"=>$arr[$j]);
}
}
}
return $result;
}
方法二:同时从两头向中间靠拢查找法,时间复杂度O(n)
function search2nums2($arr,$s) {
$high = count($arr) - 1;
$low = 0;
while($low < $high) {
$sum = $arr[$low]+$arr[$high];
if($sum == $s) {
$result = array("a"=>$arr[$low],"b"=>$arr[$high]);
return $result;
}
if($sum > $s)
$high--;
else
$low++;
}
return -1;
}
AC代码:
#include<stdio.h>
int a[1000005];
int main() {
int i, n, k;
while(scanf("%d %d", &n, &k) != EOF) {
for(i = 0; i < n; i++) {
scanf("%d", &a[i]);
}
int start = 0, end = n-1;
while(a[end/2] > k) {
end /= 2;
}
while(start < end) {
int sum = a[start] + a[end];
if(sum == k) {
break;
}
else if (sum > k) {
end--;
}
else {
start++;
}
}
if(start < end) {
printf("%d %d\n", a[start], a[end]);
}
else {
printf("-1 -1\n");
}
}
return 0;
}
/**************************************************************
Problem: 1352
User: wusuopuBUPT
Language: C
Result: Accepted
Time:1490 ms
Memory:4820 kb
****************************************************************/
这里涉及到一个证明:
证明过程我在下面的给出了,参考:http://cms.math.ca/Competitions/MOCP/97-98/ps-3.html 第14题
图示: