一、给定 个大整数 和 ,它们分别有 位和 位数字,且 。 当 比 小很多时,设计一个算法用 时间求出 的值。说明分析思路,写出伪代码,并写出算法复杂度分析过程。
解:
考虑到 比 小很多,可以把m位乘n位的问题拆解为多个m位相乘的问题,然后利用已经得出的m位相乘的优化算法进行计算。
将 分解为 段,使得每段为 位,那么类似大整数乘法的计算方法,这里计算 就相当于计算 次 位的乘法运算,然后在进行 次加法。利用已经知道的分治法求 位乘积复杂度为 ,所以求 的时间复杂度为 .
伪代码:
/**
*计算位数为m,n,且m<n的两十进制数乘积,使得时间复杂度为O(nm^log(3/2))
*/
//十进制的同位大整数乘法,且位数为n.
public static int bigMul(int x,int y,int n){
if(n == 1){
return x*y;
}
int k = n/2;
int b = x % pow(10,n/2);
int a = x / pow(10,n/2);
int d = y % pow(10,n/2);
int c = y / pow(10,n/2);
return bigMul(a,c,k)*pow(2,2*k)+((a-b)*(d-c)+bigMul(a,c,k)+bigMul(b,d,k))*pow(2,k)+bigMul(b,d,k);
}
public static int main(){
Scenner(int u,int v,int m,int n); //输入u,v,m,n
int res=0; //结果
int divide_V[n/m]; //定义存放将v分为n/m个长为m的数的数组
//将v划分并存入数组
for i=0 to i=n/m-1:
divide_V[i] = v%pow(10,m);
v /= pow(10,m);
//将数组内的数与m使用上面定义的函数分别相乘,再分别乘以对相应段的位数,如2343->23 43,23参与乘法后还要乘10的2次方,最后全部相加
for i=0 to i=n/m-1:
res += bigMul(u,divide_V[i],m) * i*pow(10,m);//第i段的应该补的位数恰为i*10的m次方
return res;
}
二、 设 个不同的整数(可能为正整数、负整数或者0)排序后存于数组 中。 设计一个算法,判断数组中是否存在不动点(若元素 等于 , 即 ,则此元素为不动点)。说明分析思路,写出伪代码,并写出算法复杂度分析过程。
解:
因为每个数都是整数,并且数组是升序的,假设其中某个位置的A[i] = i,那么可以肯定的值,之前的A[x] > x,之后的A[x] < x,那么这个问题除了判断相等的条件不同,其他和课上讲的二分搜索几乎一样,所以可以和二分搜索一样使用分治法和递归进行计算。
因为每次都是执行二分操作,每次递归中间的操作复杂度都为 ,所以,总的复杂度的递归表达式为
由主方法得时间复杂度为:
伪代码:
public static int hasPoint(int start, int end,int T[]){
int mid = (end - start) / 2 + start;
if(start > end):
return false;
if(T[mid] == mid):
return true;
else if(T[mid]<mid):
start = mid+1; //此时值小于下标,应该在右边
return hasPoint(start,end,T);
else if(T(mid)>mid) //此时值大于下标,那么可能的值就在左边
end = mid-1;
return hasPoint(start,end T);
return false;
}