转载请注明出处:http://blog.csdn.net/ns_code/article/details/24933341


题目描写叙述:
输入一个递增排序的数组和一个数字S,在数组中查找两个数,是的他们的和正好是S。假设有多对数字的和等于S,输出两个数的乘积最小的。

输入:
每一个測试案例包括两行:
第一行包括一个整数n和k,n表示数组中的元素个数,k表示两数之和。当中1 <= n <= 10^6,k为int
第二行包括n个整数。每一个数组均为int类型。
输出:
相应每一个測试案例,输出两个数,小的先输出。假设找不到,则输出“-1 -1”
例子输入:
  1. 6 15
  2. 1 2 4 7 11 15
例子输出:
  1. 4 11

    思路

最直接的做法是暴力法,两个for循环,时间复杂度为O(n*n)。可是这样没有充分利用升序数组这一前提。我们假设数组为A,长度为len,给定的和为sum,最好的方法是先用数组的第一个数A[low]和最后一个数A[high]相加,看是否等于sum,假设等于sum。则找到了一组数。返回true,假设大于sum,则将较大的数向前移动一位,即high--,此时变成了第一个和倒数第二个数相加,假设小于sum,则将较小的数向后移动一位,即low++。此时变成了第二个和最后一个数相加。依此类推,假设low==high时还未找到和为sum的一组数,则返回false。

该算法的时间复杂度为O(n),空间复杂度为O(1)。

针对该方法须要给出一些证明,证明例如以下:

对于一个升序数列A1,A2,...Ak k>=3,假设A1+Ak大于sum。那么考察k-1个数对和A1+Ak,A2+Ak,...Ak-1+Ak有sum<A1+Ak<=A2+Ak<=,...<=Ak-1+Ak。也就是说,Ak与数列中其他不论什么数的和都不可能等于sum,因此抛弃Ak这个数,对结果没有影响。A1+Ak假设小于sum的话,同理抛弃A1这个数对结果没有影响。

该方法对随意的整数数组都适合。另外,要输出乘积最小的一组,不是必需将所有的结果保存起来,我们由以下我们高中时很熟悉的数学公式能够证明最左边和最右边的两个符合要求的数的乘积最小。

当a+b = c时,ab<=(a+b)的平方/4,当且仅当a==b时,ab取得最大值,二者相差越远,乘积越小。

    aC代码例如以下:

  1. /****************************************************************************************************
  2. 题目:输入一个已经按升序排序过的数组和一个数字,在数组中查找两个数,使得它们的和正好是输入的那个数字。
  3.  
  4. 要求时间复杂度是O(n)。假设有多对数字的和等于输入的数字。输出随意一对就可以。
  5. 比如输入数组1、2、4、7、11、15和数字15。
  6.  
  7. 因为4+11=15,因此输出4和11。
  8. *****************************************************************************************************/
  9. #include<stdio.h>
  10. #include<stdbool.h>
  11. /*
  12. 在升序数组A中找出和为sum的随意两个元素。保存在a和b中
  13. */
  14. bool FindTwoNumSum(int *A,int len,int sum,int *a,int *b)
  15. {
  16. if(A==NULL || len<2)
  17. return false;
  18. int low = 0;
  19. int high = len-1;
  20. while(low<high)
  21. {
  22. if(A[low]+A[high] == sum)
  23. {
  24. *a = A[low];
  25. *b = A[high];
  26. return true;
  27. }
  28. else if(A[low]+A[high] < sum)
  29. low++;
  30. else
  31. high--;
  32. }
  33. return false;
  34. }
  35.  
  36. int main()
  37. {
  38. int n,k;
  39. static int A[1000000];
  40. while(scanf("%d %d",&n,&k) != EOF)
  41. {
  42. int i;
  43. for(i=0;i<n;i++)
  44. scanf("%d",A+i);
  45.  
  46. int a,b;
  47. bool can = FindTwoNumSum(A,n,k,&a,&b);
  48. if(can)
  49. printf("%d %d\n",a,b);
  50. else
  51. printf("-1 -1\n");
  52. }
  53.  
  54. return 0;
  55. }
/**************************************************************
    Problem: 1352
    User: mmc_maodun
    Language: C
    Result: Accepted
    Time:1460 ms
    Memory:4820 kb
****************************************************************/   

我们如今来拓展一下,假设数组是乱序的,并且规定数组中的元素所有为非负整数,相同给定一个数sum,在数组中找出随意两个数。使二者的和为sum。

    因为题目中限定了数组中的元素为非负整数,因此我们能够用哈希数组,开辟一个长度为sum的bool数组B[sum]。并所有初始化为false,对数组A进行一次遍历,假设当前的元素A[i]大于sum。则直接跳过。否则,继续作例如以下推断。假设B[A[i]]为false,则将B[sum-A[i]]置为ture。这样当继续向后遍历时,假设有B[A[i]]为true。则有符合条件的两个数,分别为A[i]和sum-A[i]。假设遍历A结束后依旧没有发现有B[A[i]]为true的元素。则说明找不到符合条件的元素。
    该算法的时间复杂度为O(n),但空间复杂度为O(sum)。

或者假设知道非负整数数组A的最大值为MAX,则也能够开辟一个MAX大小的bool数组。思路是一样的。

    完整代码例如以下:
  1. /****************************************************************************************************
  2. 题目:输入一个无序的非负整数数组和一个数字,在数组中查找两个数,使得它们的和正好是输入的那个数字。
  3. 要求时间复杂度是O(n)。
  4.  
  5. 假设有多对数字的和等于输入的数字。输出随意一对就可以。
  6. 比如输入数组1、7、4、11、6、15和数字15。因为4+11=15。因此输出4和11。
  7.  
  8. *****************************************************************************************************/
  9. #include<stdio.h>
  10. #include<stdlib.h>
  11.  
  12. /*
  13. 在无序数组A中找出和为sum的随意两个元素。保存在a和b中
  14. */
  15. bool FindTwoNumSum(int *A,int len,int sum,int *a,int *b)
  16. {
  17. if(A==NULL || len<2)
  18. return false;
  19. //各元素均被初始化为false的bool数组
  20. bool *B = (bool*)calloc(sum,sizeof(bool));
  21. if(B == NULL)
  22. exit(EXIT_FAILURE);
  23. int i;
  24. for(i=0;i<len;i++)
  25. {
  26. if(A[i]>sum)
  27. continue;
  28. if(B[A[i]] == false)
  29. B[sum-A[i]] = true;
  30. else
  31. {
  32. *a = A[i];
  33. *b = sum-A[i];
  34. free(B);
  35. B = NULL;
  36. return true;
  37. }
  38. }
  39. free(B);
  40. B = NULL;
  41. return false;
  42. }
  43.  
  44. int main()
  45. {
  46. int A[] = {19,3,9,7,12,20,17,18,1,16};
  47. int len = 10;
  48. int sum = 24;
  49. int a,b;
  50. if(FindTwoNumSum(A,len,sum,&a,&b))
  51. printf("Find two nums,they are:\n%d and %d\n",a,b);
  52. else
  53. printf("Not find\n");
  54. return 0;
  55. }

測试结果:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbnNfY29kZQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" />

【剑指offer】和为定值的两个数的更多相关文章

  1. 剑指offer用位运算实现两个数相加,及python相关的位操作

    题目:写一个函数,求两个整数之和,要求在函数体内不得使用+.-.*./四则运算符号. 代码: # -*- coding:utf-8 -*-class Solution:    def Add(self ...

  2. 剑指Offer - 九度1509 - 树中两个结点的最低公共祖先

    剑指Offer - 九度1509 - 树中两个结点的最低公共祖先2014-02-07 01:04 题目描述: 给定一棵树,同时给出树中的两个结点,求它们的最低公共祖先. 输入: 输入可能包含多个测试样 ...

  3. 剑指Offer - 九度1519 - 合并两个排序的链表

    剑指Offer - 九度1519 - 合并两个排序的链表2013-11-30 22:04 题目描述: 输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则.(hi ...

  4. 剑指Offer - 九度1512 - 用两个栈实现队列

    剑指Offer - 九度1512 - 用两个栈实现队列2013-11-29 21:23 题目描述: 用两个栈来实现一个队列,完成队列的Push和Pop操作.队列中的元素为int类型. 输入: 每个输入 ...

  5. leetcode 338. Counting Bits,剑指offer二进制中1的个数

    leetcode是求当前所有数的二进制中1的个数,剑指offer上是求某一个数二进制中1的个数 https://www.cnblogs.com/grandyang/p/5294255.html 第三种 ...

  6. C++版 - 剑指offer之面试题37:两个链表的第一个公共结点[LeetCode 160] 解题报告

    剑指offer之面试题37 两个链表的第一个公共结点 提交网址: http://www.nowcoder.com/practice/6ab1d9a29e88450685099d45c9e31e46?t ...

  7. 剑指Offer 和为S的两个数字

    题目描述 输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的. 输出描述: 对应每个测试案例,输出两个数,小的先输出. 思路 ...

  8. 剑指Offer——和为S的两个数字

    题目描述: 输入一个递增排序的数组和一个数字S,在数组中查找两个数,是的他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的.   输入描述: 对应每个测试案例,输出两个数,小的先输出. ...

  9. 剑指Offer——二进制中1的个数

    题目描述: 输入一个整数,输出该数二进制表示中1的个数.其中负数用补码表示. 分析: 加入一个数的二进制位是XXX...XXX1000...000,那么这个数减去1,就会变成XXX...XXX0111 ...

  10. 剑指offer第二版-9.用两个栈实现队列

    描述:使用两个栈实现一个队列.队列中实现尾部插入和头部删除函数. 思路:stack1负责插入,stack2负责弹出,如果stack2为空了,将stack1的元素依次弹出并存放到stack2中,之后对s ...

随机推荐

  1. MSDN 杂志:UI 前沿技术 - WPF 中的多点触控操作事件

    原文  MSDN 杂志:UI 前沿技术 - WPF 中的多点触控操作事件 UI 前沿技术 WPF 中的多点触控操作事件 Charles Petzold 下载代码示例 就在过去几年,多点触控还只是科幻电 ...

  2. ajaxSubmit提交文件表单不执行success

    先描述一下我遇到的问题,系统里所有的表单都用ajaxSubmit来提交,成功回调success函数,普通表单都是没有问题的,但是有文件上传的表单就不行了,不会回调success,经验证会回调compl ...

  3. javascript每日一练(一)——javascript基础

    一.javascript的组成 ECMAScript DOM BOM 二.变量类型 常见类型有:number, string, boolean, undefined, object, function ...

  4. 修改OpenSSL默认编译出的动态库文件名称

    在 Windows 平台上调用动态链接库 dll 文件时,有两种方式:a) 隐式的加载时链接:使用 *.lib (导入库)文件,在 IDE 的链接器相关设置中加入导入库 lib 文件的名称,或在程序中 ...

  5. 2014/08/24——升级stepbystep修复tc不刷新问题并加入杭电bc

    问题: 自从tc站点升级以后做题统计的tc一栏就不刷新了,为此全哥也更新了一下stepbystep的配置文件什么的,我仅仅要将其挂到server上即可了. 由于加了杭电的bc,看来这事儿不easy.还 ...

  6. CSS中position详解与常见应用实现

    在web前台开发时候,我们必不可少的会用到postion属性进行布局定位.今天总结了一下position知识点,与常用功能与大家分享,欢迎大家交流指正. 首先我们对postion属性进行详解. 在CS ...

  7. AngelHack China 2013 招组队成员

    AngelHack China 2013 connect me

  8. 一点一滴完全突破KAZE特征检测算法,从各向异性扩散滤波开始(1)

    ECCV2012中出现了一种比SIFT更稳定的特征检测算法KAZE.尽管,这个算法是几个法国人提出的,但是算法却有一个日文的名字.KAZE是日语‘风’的谐音,最近宣布退休的宫崎骏所拍摄的影片“起风了” ...

  9. Android滑动菜单框架完全解析,教你如何一分钟实现滑动菜单特效

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/8744400 之前我向大家介绍了史上最简单的滑动菜单的实现方式,相信大家都还记得.如 ...

  10. CWnd中PreCreateWindow、PreSubclassWindow、SubclassWindow的区别

    http://blog.csdn.net/swimmer2000/archive/2007/10/30/1856213.aspx MFC(VC6.0)的CWnd及其子类中,有如下三个函数:     / ...