找出和为S的两个数字

57 篇文章 3 订阅

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

图示:



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值