算法导论 - 2.3-7 确定集合S中是否存在两个其和刚好为x的元素

描述一个运行时间为O(nlgn)的算法,给定n个整数的集合S和另一个整数x,该算法能确定S中是否存在两个其和刚好为x的元素。

这里给出两种算法,都要求先用归并排序算法(merge sort)把集合S中元素从小到大排好序,这一步运行时间为O(nlgn)

第一种算法比较简单,即对集合S中每一个整数a,利用二分搜索法(Binary Search)在排好序的集合S中搜索(x - a)是否存在,如果存在则返回true. 如果每个集合S的整数a都无法在S中找到对应的(x - a),则算法返回false. 这一步的运行时间也是O(nlgn)。两步结合起来,整个算法运行时间保持为O(nlgn)。

第二种算法同样基于集合S中元素已从小到大排好序。

1:    Using Merge Sort to sort the array A in time O(nlgn)

2:    i = 1

3:    j = n

4:    while i < j

5:        if A[i] + A[j] == x

6:            return true

7:        elseif A[i] + A[j] < x

8:            i = i + 1

9:        else

10:          j = j - 1

11:    return false

line 2 - 11的运行时间是O(n),因为即j - i的值从n - 1逐渐减少到1,每循环一次就减1. 整个算法运行时间为O(nlgn).

这个算法比较巧妙,关键是如何证明它的正确性呢?

这里用到两个性质:

  1. 如果A[i] + A[j] < x, 则对所有的k < j,一定有A[i] + A[k] < x
  2. 如果A[i] + A[j] > x, 则对所有的k > i,一定有A[k] + A[j] > x

反证法:假设算法返回false,但集合S中存在A[i]和A[j] (i < j), A[i] + A[j] = x, 也就是在算法循环过程中,这一对(i, j)没有被检查到。

case 1: 假设存在k,j < k <= n, A[i] + A[k] 组合被算法检查到了。由于A[i] + A[j] = x,则A[i] + A[k] > x, 此时算法在检查完A[i] 和 A[k] 后会将k减1,接着检查A[i] 和 A[k - 1],如果依然有 j < k -1 ,则A[i] + A[k - 1] > x,算法会继续检查A[i] 和 A[k - 2]... 一直检查到A[i] 和 A[j],所以假设不成立。

case 2: 假设存在k, 1 <= k < i,A[k] + A[j] 组合被算法检查到了。由于A[i] + A[j] = x,则A[k] + A[j] < x, 此时算法在检查完A[k] 和 A[j] 后会将k加1,接着检查A[k + 1] 和 A[j],如果依然有 k + 1 < i ,则A[k + 1] + A[j] > x,算法会继续检查A[k + 2] 和 A[j]... 一直检查到A[i] 和 A[j],所以假设不成立。  

由于起始条件是i = 0, j = n, A[0] + A[n]一开始就被检查到了,所以上述case 1和case 2涵盖了所有除起始条件之外的情况. 所有假设情况都不成立,因此证明算法正确。

 

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值