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

代码如下:

 1 public class MergeSort {
 2     
 3     public static void sort(int [] A,int p, int r)
 4     {   
 5         if(p<r)
 6         {
 7             int q = (int) Math.floor( (p+r)/2 );
 8             sort(A,p,q);
 9             sort(A,q+1,r);
10             merge(A,p,q,r);
11         }
12         return ;
13 
14     }
15     public static void merge(int [] A, int p, int q, int r)
16     {
17         int n1 = q-p+1;
18         int n2 = r-q;
19         int [] L = new int[n1];
20         int [] R = new int[n2];
21         for(int i=0; i<n1; i++)
22           L[i] = A[p+i];
23         for(int i=0; i<n2;i++)
24             R[i]=A[q+i+1];
25         
26         int i=0;
27         int j=0;
28         int counter = p;
29         while(i<L.length && j<R.length)
30         {
31             if(L[i]<=R[j])
32             {
33                 A[counter]=L[i];
34                 i++;
35             }
36             else
37             {
38                 A[counter]=R[j];
39                 j++;
40             }
41             counter++;
42         }
43         if(i==L.length)
44         {
45             for(int k=j;k<R.length;k++)
46                 A[counter++] = R[k];
47         }
48         else
49         {
50             for(int k=i;k<L.length;k++)
51                 A[counter++] = L[k];
52         }    
53     }
54 }

 

 1 public class SumTwoEqual {
 2 
 3     /**
 4      * @param args
 5      */
 6     public static boolean TestExists(int A[],int X)
 7     {
 8         MergeSort.sort(A, 0, A.length - 1 );
 9         int i = 0;
10         int j = A.length-1;
11         while(i<j)
12         {
13             if(A[i]+A[j]==X)
14                 return true;
15             else if(A[i]+A[j] > X)
16                 j--;
17             else 
18                 i++;
19         }
20         return false;
21     }
22 
23     public static void main(String[] args) {
24         int A[] = {1,2,5,7,9,14,25,35,13,15};
25         boolean a = TestExists(A,22);
26         System.out.println(a);
27     }
28 }
算法思想很简单,就是先排序,然后从两边往中间找。除了上述的解法,还有一种方法是先排序,然后遍历所有元素a,二分查找X-a。
虽然写出了上述的算法,但是说明算法的正确性是个很难的问题。下面我给出一个大致的思路,但是不是很严谨。

我们首先假设所有的元素已经从小到大排序好了,放在数组A[1...n]中,要查询的元素是X。
1、如果A中没有任何两个元素的和是X,那么程序一定会返回false,这是很显然的。
2、所以,问题的关键在于证明:如果A中有两个元素a,b,使得a+b==X(不妨设a<=b),那么程序会保证返回true。
3、而为了证明2,则只需要证明:每一轮迭代开始之前,A[i...j]中一定包含a和b,而A[0...i-1] υ A[j+1...n]一定不包含a和b。
为什么证明了3,就能证明2呢?那是因为每一次迭代A[i...j]长度都会减一(要么i+1,要么j-1),而只要a和b还在A[i...j]中,最终一定会在某一次迭代中发现A[i]==a,A[j]==b,
从而程序返回true。最坏的情况是,迭代一直进行到i+1==j的时候,此时A[i]一定是a,A[j]一定是b。

下面归纳地证明3,即证明:每一轮迭代开始之前,A[i...j]中都包含a和b,而A[0...i-1] υ A[j+1...n]都不包含a和b。
令ik,jk表示第k轮迭代开始之前,i和j的取值。
1、第 1 轮迭代开始之前,A[i1...j1]也就是A[0...n],a和b当然包含在其中,A[0...-1]
υ A[n+1...n]是空集,当然不包含a和b。结论成立。
2、假设第 K 轮迭代开始之前,A[ik...jk]中包含a和b,而A[0...ik-1] υ A[jk+1...n]不包含a和b。
那么如果A[ik]+A[jk]==X,那么程序就返回true了。第 K+1 轮迭代不会发生。结论成立。
如果A[ik]+A[jk]>X,按照程序,jk会减1,那么第K+1轮开始之前,ik+1==ik,jk+1==jk-1。下面用反证法证明A[jk]不可能是b(A[jk]当然不可能是a)。因为如果A[jk]是b,那么
X<A[ik]+b<A[ik+1]+b<A[ik+2]+b<...<A[jk-1]+b,那么a就不可能是A[ik...jk-1]中的任何一个元素,这和初始假设A[i...j]中包含a和b矛盾。所以A[jk]不可能是b。所以a和b仍然包含在A[ik+1...jk+1]中。
如果A[i]+A[j]<X,那么A[i]不可能是a(因为b>=a,所以A[i]当然不可能是b)。因为如果A[i]是a,那么
a+A[i+1]<a+A[i+1]<a+A[i+2]<...<a+A[j]<X,那么b就不可能是A[i+1...j]中的任何一个元素,这和初始假设A[i...j]中包含a和b矛盾。
所以,如果A[i]+A[j]>X,按照程序,j会减1,也就是在在第K+1轮迭代开始之前,数据是A[i...j-1],因为A[j]不可能是b,所以A[i...j-1]中仍然包含a和b
如果A[i]+A[j]<X,i会加1,也就是在第K+1轮迭代开始之前,数据是A[i+1...j],因为A[i]不可能是a,所以A[i+1...j]仍然包含a和b。
3、由1和2可知,在每一轮迭代开始之前,A[i...j]中一定包含a和b,而A[0...i-1] υ A[j+1,n]一定不包含a和b。

证明好困难!

 
 
 

转载于:https://www.cnblogs.com/wzm-xu/p/4261233.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值