习题2.3-7:设计一个算法,对于一个给定的包含n个整数的集合S和另一个给定的整数X,该算法可以在时间内确定S中是否存在两个元素,使得它们的和恰为X。

解题思路:首先应该想到的是先用一个的排序算法对S中的元素进行排序。接下来有两种处理思路,第一种思路是遍历已经排好序了的S中的所有元素a,并采用

二分查找的方法在S中查找X-a,如果能够找到,那么说明S中确实存在两个元素的和为X,算法终止。这种思路很显然是满足的限制要求的;第二种思路是我自己

想出的一个算法,这个算法也很简单,但是其正确性不是很好证明。

思路1:

CheckSum( A[1…n] , X )
1    MergeSort( A ) //从小到大排序
2    for i = 1 to n
3        if  BinarySearch( A[1…n] , X-A[i] ) != –1 //假设BinarySearch在找不到指定元素的时候返回-1
4              return true
5    return false

思路2:

CheckSum( A[1…n] , X)
1    MergeSort( A ) //从小到大排序
2    i = 1
3    j = n
4    while( i < j)
5        if( A[i] + A[j] == X)
6             return true
7        else if( A[i] + A[j] > X)
8             j--
9        else if( A[i] + A[j] < X)
10           i++
11   return false

算法正确性证明:

思路1的正确性是显而易见的;思路2的正确性就不那么直观,其可能令人感到困惑的地方在于:思路2会不会漏掉某些情况?下面开始思路2的证明,

但是因为我也是初学,证明过程不是很严谨和规范。

首先,假设S中“不”包含两个和为X的元素,那么思路2的第5行的测试条件永远不会成真,那么最终算法一定会返回false。因此,证明思路2的正确性

便转化成证明:

若S中存在两个元素a和b,使得a+b==X,那么算法一定会返回true。(*)

为了证明(*)成立,下面首先证明思路2的算法在执行过程中满足如下的特性:

若S中存在两个元素a和b,使得a+b==X(不妨设a<=b),则在思路2的算法执行过程汇中,每一次迭代开始之前(即算法第4行执行之前),A[i…j]都包含a和b。(#)

下面采用归纳法证明(#)的成立:(令 ik,jk 分别表示第 k 轮迭代开始之前 i 和 j 的取值,A[ik…jk]表示第k轮迭代开始之前的A[i…j])

证明:
1、第 1 轮迭代开始之前,i1=1,j1=n。A[ik…jk]即为A[1…n],a和b很显然包含在A[1…n]中,结论成立。
2、若第 k 轮迭代开始之前,A[ik…jk]包含a和b。则按照算法的执行步骤:
     (1)如果A[ik]+A[jk]==X,算法返回true,算法终止。
     (2)如果A[ik]+A[jk] > X,算法使得jk值减1,即第 k+1 轮迭代开始之前,ik+1 = ik,jk+1 = jk - 1。下面证
             明A[jk]不可能是a或者b中的任何一个: 
             (2.1)因为a<b,且A[ik…jk]包含a和b,所以A[jk]不可能是a。
             (2.2)假设A[jk]等于b,因为A[]是从小到大排序的,所以,必然有:
                        A[jk]+A[jk-1] > A[jk]+A[jk-2] > A[jk]+A[jk-3] > … > A[jk]+A[ik+1] >A[jk]+A[ik] > X,即:
                        b+A[jk-1] > b+A[jk-2] > b+A[jk-3] > … > b+A[ik+1] >b+A[ik] > X
                        也就是说a不可能是A[ik…jk-1]中的任何一个元素,这和前提:A[ik…jk]包含a和b 矛盾,所以假
                        设错误,所以A[jk]不是b。
              因为A[ik…jk]中包含a和b,而又已经证明A[jk]不是a或者b,又ik+1 = ik,jk+1 = jk - 1 ,所以,在第k+
              1轮迭代开始之前,A[ik+1…jk+1]一定包含a和b。
     (3)如果A[ik]+A[jk] < X,同理可证第k+1轮迭代开始之前A[ik+1,jk+1]一定包含a和b。 
3、由1、和2、可知,每一次迭代开始之前,A[i…j]都包含a和b。

现在(#)已经得到证明,而由(#)证(*)是很直观的。因为A[i…j]中始终包含a和b,并且每一次迭代A[i…j]的规模小一,所以,最坏的情况是迭代一直执行到i+1=j的

时候,因为此时A[i,j]包含a和b,所以A[i]一定是a,A[j]一定是b,算法检测到A[i]+A[j] = a+b=X,算法返回true。

总结:以上便是全部内容,从理论上讲思路2应该要比思路1要快(虽然它们都是)。但是很明显地,思路1的正确性更加直观。

《算法导论》2.3-7 检查集合中是否存在两数字和为指定的X--算法和证明的更多相关文章

  1. [算法导论]练习2-4.d求排列中逆序对的数量

    转载请注明:http://www.cnblogs.com/StartoverX/p/4283186.html 题目:给出一个确定在n个不同元素的任何排列中逆序对数量的算法,最坏情况需要Θ(nlgn)时 ...

  2. leetcode-1 Two Sum 找到数组中两数字和为指定和

     问题描写叙述:在一个数组(无序)中高速找出两个数字,使得两个数字之和等于一个给定的值.如果数组中肯定存在至少一组满足要求. <剑指Offer>P214(有序数组) <编程之美& ...

  3. 《算法导论》— Chapter 9 中位数和顺序统计学

    序 在算法导论的第二部分主要探讨了排序和顺序统计学,第六章~第八章讨论了堆排序.快速排序以及三种线性排序算法.该部分的最后一个章节,将讨论顺序统计方面的知识. 在一个由n个元素组成的集合中,第i个顺序 ...

  4. 算法导论 之 红黑树 - 删除[C语言]【转】

    转自:https://blog.csdn.net/qifengzou/article/details/17608863 作者:邹祁峰 邮箱:Qifeng.zou.job@hotmail.com 博客: ...

  5. not(expr|ele|fn)从匹配元素的集合中删除与指定表达式匹配的元素

    not(expr|ele|fn) 概述 从匹配元素的集合中删除与指定表达式匹配的元素   参数 exprStringV1.0 一个选择器字符串.深圳dd马达 elementDOMElementV1.0 ...

  6. C#经典算法实践,回顾往生,更是致敬《算法导论》

    该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/666 访问. 概述 本系列博文将会向大家介绍本人在钻研<算法导论 ...

  7. 集合中list、ArrayList、LinkedList、Vector的区别、Collection接口的共性方法以及数据结构的总结

    List (链表|线性表) 特点: 接口,可存放重复元素,元素存取是有序的,允许在指定位置插入元素,并通过索引来访问元素 1.创建一个用指定可视行数初始化的新滚动列表.默认情况下,不允许进行多项选择. ...

  8. list<T>集合中的Remove()、RemoveAt()、RemoveRange()、RemoveAll()的用法

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  9. 《算法导论》习题2.3-7 查找集合S中是否有两个元素和为X---Java实现

    代码如下: public class MergeSort { public static void sort(int [] A,int p, int r) { if(p<r) { int q = ...

随机推荐

  1. DEAMONTOOLS: installation

    installing daemontools .. adding -I /usr/include/errno.h to last first line of conf-cc mkdir -p /pac ...

  2. Android上掌纹识别第一步:基于OpenCV的6种肤色分割 源码和效果图

    Android上掌纹识别第一步:基于OpenCV的6种肤色分割 源码和效果图 分类: OpenCV图像处理2013-02-21 21:35 6459人阅读 评论(8) 收藏 举报   原文链接  ht ...

  3. (转)Unity3D移动平台动态读取外部文件全解析

    Unity3D移动平台动态读取外部文件全解析 c#语言规范 阅读目录 前言: 假如我想在editor里动态读取文件 移动平台的资源路径问题 移动平台读取外部文件的方法 补充: 回到目录 前言: 一直有 ...

  4. hbase建索引的两种方式

    转载自http://blog.csdn.net/ryantotti/article/details/13295325 在二级索引的实现技术上一般有几个方案: 1.      表索引 使用单独的hbas ...

  5. JS中获取页面单选框radio和复选框checkbox中当前选中的值

    单选框:单选框的name值全部相同 页面有一组单选框的元素<td><input type="radio name="radioid">满意< ...

  6. java 缓冲流

    english.txt The arrow missed the target. They rejected the union demand. Where does this road go to? ...

  7. ubuntu 12.04 安装snort acidbase相关注意事项

    一.安装Snort 1.安装libpcap 1 apt-get install libpcap-dev 2.安装snort 1 2 apt-get install snort apt-get inst ...

  8. BAT54C 二极管是如何工作的?

    这是一个多电源供电的电路:Vcc是正常供电电源(如5V,由市电变换得到),电压大于(Vcc1-Vf),正常供电时二极管不导通:Vcc1是电池供电电源,当Vcc撤掉时,DD1(上边的二极管)导通,由Vc ...

  9. 原生的ajax(json)

    function getXHR(){ if(window.XMLHttpRequest){ return new XMLHttpRequest(); }else{ try{ return new Ac ...

  10. Keepalived详细介绍简介

    1.1.Keepalived简介 Keepalived是Linux下一个轻量级别的高可用解决方案.高可用(High Avalilability,HA),其实两种不同的含义:广义来讲,是指整个系统的高可 ...