#Ex.2.22
给定两个有序表,大小分别为m和n。给出一个算法,以$O(log m+log n)$的时间找出两个列表合并后的有序列表中的第K小元素
我们从最基础的情况开始考虑,假设一个数组为空,在另一个数组中找第K小元素,很明显,如果k不超过第二个数组的长度,那么结果就是B[bLeft+k-1]
反之同理
所以,合法性判定,和终止判定如下1
2
3
4
5
6
7
8
9
10
11if (k>(aRight - aLeft + 1 + bRight - bLeft + 1))
{
cerr << "输入不合法" << endl;
return -1;
}
if (aLeft > aRight){
return B[bLeft+ k - 1];
}
if (bLeft> bRight){
return A[aLeft+ k - 1];
}
下面,我们回归一般情况下
我们取1
2int aMiddle = (aLeft + aRight) / 2;
int bMiddle = (bLeft + bRight) / 2;
首先比较$A[aMiddle]$与$B[bMiddle]$的大小
我们不妨假设$A[aMiddle]>B[bMiddle]$
如果满足$A[aMiddle]>B[bMiddle]$
那么必定有$A[aMiddle+1,…,aRight]$排在所有元素的$(aMiddle+bMiddle)$之后
同时还有$B[bLeft,…,bMiddle]$排在所有元素的$(aMiddle+bMiddle)$之前
然后那么如果1
k <= (aMiddle-aLeft)+(bMiddle-bLeft)+1
我们可以把A数组右边的部分舍弃,否则
我们可以把B数组的左边部分舍弃,并在剩余部分寻找第(k-舍弃部分的个数)
反之亦然。
代码如下1
2
3
4
5
6
7
8
9
10
11
12
13
14if (A[aMiddle] > B[bMiddle])
{
if (k <= (aMiddle - aLeft) + (bMiddle - bLeft) + 1)
FindElement(A, B, aLeft, aMiddle - 1, bLeft, bRight, k);
else
FindElement(A, B, aLeft, aRight, bMiddle + 1, bRight, k - (bMiddle - bLeft) - 1);
}
else
{
if (k <= ((aMiddle - aLeft) + (bMiddle - bLeft) + 1))
FindElement(A, B, aLeft, aRight, bLeft, bMiddle - 1, k);
else
FindElement(A, B, aMiddle + 1, aRight, bLeft, bRight, k - (aMiddle - aLeft) - 1);
}
全部代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46#include<iostream>
using namespace std;
int FindElement(int A[], int B[], int aLeft, int aRight, int bLeft, int bRight, int k);
int main()
{
int A[10] = { 1, 3, 5, 6, 7, 9, 11, 13, 15, 17 };
int B[5] = { 2, 4, 8, 10, 12, };
//int k;
//cout << "请输入k的值:";
//cin >> k;
for (int k = 1; k < 10; k++)
cout << endl << FindElement(A, B, 0, 9, 0, 4, k);
return 0;
}
int FindElement(int A[], int B[], int aLeft, int aRight, int bLeft, int bRight, int k)
{
if (k > (aRight - aLeft + 1 + bRight - bLeft + 1))
{
cerr << "输入不合法" << endl;
return -1;
}
if (aLeft > aRight){
return B[bLeft + k - 1];
}
if (bLeft > bRight){
return A[aLeft + k - 1];
}
int aMiddle = (aLeft + aRight) / 2;
int bMiddle = (bLeft + bRight) / 2;
if (A[aMiddle] > B[bMiddle])
{
if (k <= (aMiddle - aLeft) + (bMiddle - bLeft) + 1)
FindElement(A, B, aLeft, aMiddle - 1, bLeft, bRight, k);
else
FindElement(A, B, aLeft, aRight, bMiddle + 1, bRight, k - (bMiddle - bLeft + 1));
}
else
{
if (k <= ((aMiddle - aLeft) + (bMiddle - bLeft) + 1))
FindElement(A, B, aLeft, aRight, bLeft, bMiddle - 1, k);
else
FindElement(A, B, aMiddle + 1, aRight, bLeft, bRight, k - (aMiddle - aLeft + 1));
}
}
#Ex2.27
(a)
\begin{equation}
\left[
\begin{array}{ccc}
a & b \
d & e
\end{array}
\right]
^2=
\left[
\begin{array}{ccc}
a^2+bc & b(a+d) \
c(a+d) & bc+d^2
\end{array}
\right]
\end{equation}
b)
因为分治之后得到的子问题不再是平方操作了,所以该算法的运行时间不是$O(nlog25)$
#Ex2.31
算法:
$gcd = 2gcd(a/2,b/2)$, 若a,b都是偶数
$gcd(a,b/2)$, 若a是奇数,b是偶数
$gcd(|a-b|,Min(a,b))$,若a,b都是奇数
1 | int gcd(int a, int b) |