算法导论2.3-7习题解答(合并排序算法及二分查找)

时间:2023-02-22 23:54:14

CLRS 2.3-7 :请给出一个运行时间为O(nlgn)的算法,是之能在一个由n个整数构成的集合S和另一个整数x时,判断出S中是否存在有两个其和等于x的元素。

算法思想:
1.先运用合并排序进行排序 O(nlgn),
2.然后运用二分查找法寻找y,y = x - a[i];

代码如下:

 1 #include <iostream>
2 using namespace std;
3
4 void sort(int*&a, int p, int q, int r)
5 {
6 int* left =new int[q - p +1];
7 int* right =new int[r - q];
8 for(int i =0; i < q - p +1; i++)
9 left[i] = a[p + i];
10 for(int i =0; i < r - q; i++)
11 right[i] = a[q + i +1];
12
13 int m =0;
14 int n =0;
15 //书上在这里用的是在数组末尾添加一个数,即"哨兵牌"
16 //作者同时让我们不用"哨兵牌"来实现
17 //我在这里采取的是,如果到达一个数组的末尾,
18 //那么另外一个数组的剩余元素就不用比较了,然后可以完全复制到a,见27行.
19 //时间复杂度未变,因为27行的循环紧跟20行的循环而已,你可以看到结束条件都是i<=r,j<=r,然后break
20 for(int i = p; i <= r; i++) {
21 if(left[m] <= right[n]) {
22 a[i] = left[m];
23 if(m++== q-p) {
24 for(int j = i +1; j <= r; j++)
25 a[j] = right[n++];
26 break;
27 }
28 } else {
29 a[i] = right[n];
30 if(n++== r-q-1) {
31 for(int j = i +1; j <= r; j++)
32 a[j] = left[m++];
33 break;
34 }
35 }
36 }
37
38 delete[] left;
39 delete[] right;
40 }
41 void merge(int*&a, int m, int n)
42 {
43 if(m < n) {
44 int q = (m + n)/2;
45 merge(a, m, q);
46 merge(a, q+1, n);
47 sort(a, m, q, n);
48 }
49 }
50
51 //二分查找
52 bool binary_search(int* a, int n, int goal)
53 {
54 int middle = (n -1)/2;
55 int high = n -1;
56 int low =0;
57 while(low <= high) {
58 if(a[middle] == goal)
59 return true;
60 else if(a[middle] >= goal)
61 high = middle -1;
62 else
63 low = middle +1;
64 middle = (low + high)/2;
65 }
66 return false;
67 }
68
69 int main()
70 {
71 const int LEN =1000000;
72 //用max来代表最大数,你可以任意选取
73 int max =100000000;
74 int* a =new int[LEN];
75 for(int i =0; i < LEN; i++)
76 a[i] = LEN - i;
77 merge(a, 0, LEN -1);
78
79 int x;
80 cin>>x;
81 if(!(x%2)) {
82 for(int i =0; i < LEN; i++)
83 if(a[i] == x/2) {
84 a[i] = max;
85 break;
86 }
87 }
88
89 for(int i =0; i < LEN; i++)
90 if(binary_search(a, LEN, x - a[i])) {
91 cout<<"YES"<<endl;
92 break;
93 }
94
95 delete a;
96 return 0;
97 }