算法题02:递归:大整数乘法的变式、二分搜索

一、给定 2 2 个大整数 u u v v ,它们分别有 m m 位和 n n 位数字,且 m n m\le n 。 当 m m n n 小很多时,设计一个算法用 O ( n m log ( 3 / 2 ) ) O(nm^{\log(3/2)}) 时间求出 u v uv 的值。说明分析思路,写出伪代码,并写出算法复杂度分析过程。

​ 考虑到 m m n n 小很多,可以把m位乘n位的问题拆解为多个m位相乘的问题,然后利用已经得出的m位相乘的优化算法进行计算。

​ 将 v v 分解为 n / m n/m 段,使得每段为 m m 位,那么类似大整数乘法的计算方法,这里计算 u v uv 就相当于计算 n / m n/m m m 位的乘法运算,然后在进行 n / m 1 n/m-1 次加法。利用已经知道的分治法求 m m 位乘积复杂度为 O ( m l o g 3 ) O(m^{log^{3}}) ,所以求 u v uv 的时间复杂度为 O ( ( n / m ) m l o g 3 ) + O ( n / m ) = O ( n m l o g ( 3 / 2 ) ) O((n/m)m^{log^{3}}) + O(n/m) = O(nm^{log(3/2)}) .

伪代码

/**
 *计算位数为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;
}

二、 设 n n 不同的整数(可能为正整数、负整数或者0)排序后存于数组 T [ 0 : n 1 ] T[0:n-1] 中。 设计一个算法,判断数组中是否存在不动点(若元素 T [ i ] T[i] 等于 i i , 即 T [ i ] = i T[i]=i ,则此元素为不动点)。说明分析思路,写出伪代码,并写出算法复杂度分析过程。

解:

​ 因为每个数都是整数,并且数组是升序的,假设其中某个位置的A[i] = i,那么可以肯定的值,之前的A[x] > x,之后的A[x] < x,那么这个问题除了判断相等的条件不同,其他和课上讲的二分搜索几乎一样,所以可以和二分搜索一样使用分治法和递归进行计算。

​ 因为每次都是执行二分操作,每次递归中间的操作复杂度都为 O ( 1 ) O(1) ,所以,总的复杂度的递归表达式为

T(n) = T(n/2) + O(1)

​ 由主方法得时间复杂度为: O ( l o g n ) O(logn)

伪代码:

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;
}
发布了27 篇原创文章 · 获赞 19 · 访问量 4536

猜你喜欢

转载自blog.csdn.net/qq_43617268/article/details/104947480