九度OJ 1352:和为S的两个数字 (查找)

时间限制:2 秒

内存限制:32 兆

特殊判题:

提交:3160

解决:833

题目描述:
输入一个递增排序的数组和一个数字S,在数组中查找两个数,是的他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。
输入:
每个测试案例包括两行:
第一行包含一个整数n和k,n表示数组中的元素个数,k表示两数之和。其中1 <= n <= 10^6,k为int
第二行包含n个整数,每个数组均为int类型。
输出:
对应每个测试案例,输出两个数,小的先输出。如果找不到,则输出“-1 -1”
样例输入:
6 15
1 2 4 7 11 15
样例输出:
4 11

思路:

朴素思路是遍历查找,也就是我最初代码中用的方法。复杂度NlogN。

但后来想想,其实根据4xy = (x+y)^2-(x-y)^2,两个数的和一定,那么差越大,积越小,其实只需要找差最大的这一对数即可。可以省掉很多多余的查找。但最坏的复杂度仍然是NlogN。

进一步的优化思路能够将复杂度下降到线性:两个数A和B分别从最左侧和最右侧向中间搜索,每次循环中,固定A,从上次搜索到的B开始下降搜索。最终的复杂度将是N。

PS:这个题的测试数据不是太好,我试了朴素思路和优化思路,结果竟然相差不大。


代码:

#include <stdio.h>
 
#define N 1000000
 
int search(int *a, int begin, int end, int x)
{
    int len = end - begin;
    if (len <= 0)
        return -1;
    if (len == 1)
    {
        if (a[begin] == x)
            return begin;
        else
            return -1;
    }
 
    int mid = begin + len/2;
    if (a[mid] == x)
        return mid;
    else if (x < a[mid])
        return search(a, begin, mid, x);
    else
        return search(a, mid+1, end, x);
}
 
int main(void)
{
    int n, k, i, j;
    int a[N];
 
    while (scanf("%d%d", &n, &k) != EOF)
    {
        for(i=0; i<n; i++)
            scanf("%d", &a[i]);
 
        for (i=0; i<n-1; i++)
        {
            j = search(a, i+1, n, k-a[i]);
            if (j > i)
                break;
            else
                continue;
        }
 
        if (i == n-1)
            printf("-1 -1\n");
        else
            printf("%d %d\n", a[i], a[j]);
    }
 
    return 0;
}
/**************************************************************
    Problem: 1352
    User: liangrx06
    Language: C
    Result: Accepted
    Time:1520 ms
    Memory:4748 kb
****************************************************************/

优化代码:

<pre name="code" class="cpp">#include <stdio.h>
 
#define N 1000000
 
int main(void)
{
    int n, k, i, j;
    int a[N];
 
    while (scanf("%d%d", &n, &k) != EOF)
    {
        for(i=0; i<n; i++)
            scanf("%d", &a[i]);
 
        i = 0, j = n-1;
        while (i < j) {
            if (a[i] + a[j] == k)
                break;
            else if (a[i] + a[j] < k)
                i++;
            else
                j--;
        }
 
        if (i == j)
            printf("-1 -1\n");
        else
            printf("%d %d\n", a[i], a[j]);
    }
 
    return 0;
}
/**************************************************************
    Problem: 1352
    User: liangrx06
    Language: C
    Result: Accepted
    Time:1450 ms
    Memory:4748 kb
****************************************************************/


 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值