@rg070836rg
2015-11-01T22:17:02.000000Z
字数 2708
阅读 1545
算法概论作业
给定两个有序表,大小分别为m和n。给出一个算法,以
O(logm+logn) 的时间找出两个列表合并后的有序列表中的第K小元素
我们从最基础的情况开始考虑,假设一个数组为空,在另一个数组中找第K小元素,很明显,如果k不超过第二个数组的长度,那么结果就是B[bLeft+k-1]
反之同理
所以,合法性判定,和终止判定如下
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;
首先比较
我们不妨假设
如果满足
那么必定有
A[aMiddle+1,...,aRight] 排在所有元素的(aMiddle+bMiddle) 之后
同时还有B[bLeft,...,bMiddle] 排在所有元素的(aMiddle+bMiddle) 之前
然后那么如果
k <= (aMiddle-aLeft)+(bMiddle-bLeft)+1
我们可以把A数组右边的部分舍弃,否则
我们可以把B数组的左边部分舍弃,并在剩余部分寻找第(k-舍弃部分的个数)
反之亦然。
代码如下
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);
}
全部代码如下:
#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));
}
}
(a)
b)
因为分治之后得到的子问题不再是平方操作了,所以该算法的运行时间不是
算法:
int gcd(int a, int b)
{
if(a == 0) return b;
if(b == 0) return a;
if(a % 2 == 0 && b % 2 == 0) return 2 * gcd(a/2, b/2);
else if(a % 2 == 0) return gcd(a/2 , b);
else if(b % 2 == 0) return gcd(a, b/2);
else return gcd(abs(a - b), Min(a, b));
}
int Min(int a,int b)
{
if (a >= b)
{
return b;
}
else
return a;
}