前提,在一个已经排序完成的A阵列中
Divide : 元素x和A阵列的中间元素进行比较
Conquer : 在其中一个子阵列中进行递回,如果x小於A阵列的中间元素,就在左子阵列进行递回。
Combine : 没有
递回关系式:
发现这个递回关系式符合关系式,可以使用主定理(master method)求解,代入,得到,这个结果大於(主方法case 2),因此该递回式的解为
,得到解。
int binary_search(vector<int> &array, int min, int max, int target)
{
int mid = 0;
if (max > min)
{
mid = start + (end - start)/2
if(array[mid] == target)
{
return array[mid];
}
if (target < array[mid])
{
return binary_search(array, min, mid - 1, target);
}
else if(target > array[mid])
{
return binary_search(array, mid + 1, max, target);
}
}
return -1;
}
正常一般情况,要计算x的n次方,即为将x * x * x....进行n次,每一次的乘法需要一个常数时间c,总时间为cn,用进行表示。
我们引入分治法的想法,去解决这个问题,我们可以把这个问题进行分解
,当n为偶数时,如果我们得知的结果,只剩下需要计算,这需要一个常数时间,因此,复杂度就会变成原来的一半,将这个递回关系写出
,如同二分搜寻法的结果,得出的解为,这个方法就称为native recursive squaring。
定义
时间复杂度 : , 为黄金比例常数,
这是一个指数型的时间复杂度,而我们希望他可以式多项式的时间复杂度。
如果我们将费波那契数列的递回情况画成一棵树,会发现存在许多相同的子树,也就是有许多情况不断地重复发生,以至於浪费了许多时间,我们可以将计算过的结果放在一个阵列当中(动态规划的想法),此持我们在计算时间就会是(我们只需要知道前n项相加即可)。
native recursive squaring(朴素平方递回)的时间复杂度为,如果我们将取整数到与其最接近的整数,我们会发现其结果就是第n位的费波那契数。
但是在真实的机器中,这个方法是不可行的,原因是因为我们必须使用浮点数表示和,直接取整可能会有错误发生。
我们可以利用费波那契数的特性,来使用平方递回
2*2的矩阵和2*2的矩阵进行乘法运算得出来的结果依然是2*2的矩阵,规模不会变大,我们使用分治法的出的时间复杂度依然会保持在
下面使用数学归纳法进行证明:
我们将上面进行结合,得到
根据数学归纳法,证明完毕。
Input: , ,
Output:
假设是一个2*2的矩阵乘法,矩阵C总共有4项需要计算,每一个项需要2步的计算
若有一个n*n的矩阵乘法。矩阵C需要项需要计算,每一项需要n步,整体复杂度为
int main(void)
{
int A[2][2] = {{2, 3}, {4, 5}};
int B[2][2] = {{6, 7}, {8, 9}};
int C[2][2] = {{0, 0}, {0, 0}};
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
for (int k = 0; k < 2; k++)
{
C[i][j] = C[i][j] + A[i][k] * B[k][j];
}
}
}
我们使用分治法降低时间复杂度,每个矩阵有数字(因为是方阵),上面分治法的想法都是将规模为n的问题分解成n/2的两个子问题,我们希望一个n*n的矩阵可以转化为两个n/2*n/2规模的矩阵,我们可以使用分块矩阵(block matrix)的想法
这个例子我们将4*4的矩阵看做4个2*2的矩阵,也就是将n*n的矩阵拆分成数个n/2*n/2的矩阵
我们可以得到以下的关系
我们将其视为A矩阵,将其视为B矩阵,将其视为C矩阵,我们要求的C矩阵的结果,就是将上面结果计算并组合之後就能够得到,每一个字母我们可以想像成是一个n/2规模的矩阵,我们需要不断的递回计算乘积,直到每一个字母是一个数字。
在上面这个例子中,我们可以得到我们需要进行8次的递回运算,也就是,以及4次的求和运算,将两个矩阵相加所需要的时间复杂度是,矩阵加法的复杂度已经无法再减少了,目前矩阵乘法的总复杂度为:
,发现这个递回关系式符合关系式,因此使用主定理来解出这个递回式
代入得到,,属於case 1.
因此结果为,也就是
这个想法的思路为,我们必须绕过这些乘法,也就是减少乘法发生的次数,上面这个例子中,我们需要进行8次,需要进行8次乘法运算并加总才能够得到C,我们尝试减少乘法发生的次数,以加快矩阵乘法的速度。在这个演算法中,我们可以让乘法发生的次数降低到7次。
我们可以在的时间完成这一些操作,之後我们将这四项元素用上面的符号进行表示:
我们可以确认看看这一些结果,以u作为例子
得到,会发现跟我们上方正常进行矩阵乘法运算的结果是相同的
这个演算法使用分治法的思路如下
Divide : 将A矩阵和B矩阵进行拆分,然後求得一些乘积项,也就是计算出所有的P,这一步需要
Conquer : 递回的方式处理每一个,得到7个乘积
Combine : 结合每一项P的结果,得出,需要
整个演算法的递回关系式为,发现这个递回关系式符合关系式,因此使用主定理来解出这个递回式
代入得到,,属於case 1.因此时间复杂度为,比好,但不是最好的演算法,目前最好的矩阵乘法演算法为Coppersmith-Winograd,复杂度为
参考资料: Introduction to algorithms 3rd
<<: 【Day19】 用 4 种不同的 GAN 模型生成音乐简介
>>: 初学者跪着学JavaScript Day4 : 宣告:let、const
大家午安~ 在第 8、9 天我们完成 Data Collection 以及 Google Analy...
Key-value 版本兼容警告 如果key不加引号 $data=[ john1=>1.2, ...
今天要介绍的是 generic classes 上面可以看到出现了很多错误,因为 data、item...
今天把dialogfragment也搭配上bindnig然後试着把dialog的动作移到dialog...
设置CSS样式大小时,会使用到各种不同的单位,尤其现在都制作响应式网站,用错单位,就会针对不同尺寸调...