divide and conquer
来源:互联网 发布:国产机器人仿真软件 编辑:程序博客网 时间:2024/04/29 03:13
刚刚被老妈拉出去健身,所以更的晚了一些。。。
今天这部分是只有视频里面有书上没有的
首先回忆一下上个话题,我们为什么要讲递归式,原因就是分治法中要用到递归式来获得其复杂度。从而评判算法的好坏。
对于一个递归式: T(n) = aT(n/b)+Theta(1)
a表示子问题的个数,n/b表示子问题的大小,Theta(1)表示合并子问题的时候的开销
这里需要注意一点,子问题不能是有重复的情况,比如说算斐波那契数列,用分治法是指数级别的开销(Theta(phi^n),其中phi为黄金分割数),用自底向上的递推则只有Theta(n)的开销。说到斐波那契数列,其实有小于O(n)的算法,一会儿总结里会提到。
接下来写个总结吧:
merge sort
basic idea是先把一个数组分成两半,分别进行merge sort(复杂度是2*O(n/2)),然后把已经merge好的两个数组merge了(复杂度是Theta(n)).
写出递归式是T(n) = 2T(n/2)+Theta(n)
显然,这里我们的两个T(n/2)虽然看上去一样,但并非重复计算,而是分别对两半进行merge,故而不存在冗余计算的情况.
这个大家应该非常熟悉,master method 告诉我们复杂度是nlogn
binary search
这个大家肯定都写过,也能脱口而出它的复杂度是logn
但是既然我们是钻研算法的人,肯定不能满足于此吧。
我先给出它的递归式:T(n) = T(n/2)+Theta(1)
T(n)是指对n个数进行二分查找的复杂度, T(n/2)是指对n/2个数进行二分查找的复杂度,Theta(1)是比较要查找的数和数组中的第n/2个数的运算复杂度
同理,master method 告诉我们上面的递归式的复杂度是logn。
powering a number
这也是很经典的问题,简单的说就是假设计算机不会算乘方,你写一个函数计算x^n。
一个最简单明了的想法就是这样写
int f(float x, int n){ if (n != 1) return x*f(x,n-1); return x;}但是稍微想想就会发现我们这里有很多重复计算的地方。比如说,你算x^4,其实只需要x^2再算平方就可以了,并不需要x^3。
这个算法的复杂度是多少呢?O(n),虽然不算大,但我们有更好的。
正如我刚刚所说,算x^n只需要算x^(n/2)或者算x^(n-1)/2就可以了,这取决于n的奇偶性。
我给出它的计算式:
x^n = x^(n/2)*x^(n/2) if n is even
x^n = (x^(n-1)/2)*(x^(n-1)/2)*x if n is odd
再给出它的递归式(这里我们并不在意它的取整情况):
T(n) = T(n/2)+Theta(1)
它的复杂度是logn
给出代码
int f(float x, int n){ if(n == 1) return x; if(n%2 == 0) { int temp = f(x,n/2); return temp*temp; } else { int temp = f(x,(n-1)/2); return temp*temp*x; }}
斐波那契数列
类似于上面的问题,简单的做法是递归的计算
f(n) = f(n-1) + f(n-2)
如果你愿意画一下递归树会发现里面重复计算的子树太多了,简直一直都在重复计算。
事实上这个复杂度是指数级别的,高达O(phi^n),其中phi = (sqrt(5)-1) / 2
但如果我们顺序递推f(n),每次要计算f(n)时f(n-1)和f(n-2)都已经计算好了。这个计算复杂度是O(n)。
事实上有更牛X的方法,但是一般人估计想不到了。斐波那契数其实有个性质,就是round(phi^n/sqrt(5))就是f(n)。这样可以用我们刚才说的计算数的power的方法计算f(n),复杂度是logn。是不是很厉害呢?
不幸的是由于种种原因,这种算法并不能真正在计算机上实现,因为现在的计算机都是浮点型的计算机,根号5和phi其实都是被一些固定位数的浮点数来表示,在计算过程中会失去一些位,结果就是取整的时候得不到正确的答案。
最后教授介绍了一种复杂度为log(n)且可行的方法。((F(n+1), F(n)) (F(n), F(n-1))) = ((1,1) (1,0))^n,这是一个用矩阵来计算的方法,我给出自己写的实例代码。
可以用一维矩阵替代二维
#include <stdio.h>int a[2][2] = {{1,1},{1,0}};int* matrix_multi(int *A, int *B){int i, j, k;int *temp = new int[4];for(i = 0; i < 2; i ++){for (j = 0; j < 2; j++){ *(temp+2*i+j) = 0; for (k = 0; k < 2; k ++){ *(temp+2*i+j) = *(temp+2*i+j) + (*(A+2*i+k)) * (*(B+2*k+j));}}}return temp; }int* f(int n){if(n < 1) return NULL;if(n == 1) return *a;if(n%2 == 0){ return matrix_multi(f(n/2), f(n/2)); } else { return matrix_multi(matrix_multi(f((n-1)/2), f((n-1)/2)), *a); }}int main(){printf("%d", *(f(10)+1));return 0;}
也可直接用二维矩阵
#include <stdio.h> int ** matrix_multi(int** A, int** B){ int ** p = new int *[2]; for (int i =0; i<2; i++){ p[i] = new int[2]; } for (int i =0; i<2; i++){ for(int j = 0; j < 2; j++){ for (int k = 0; k < 2; k++){ p[i][j] = p[i][j] + A[i][k]*B[k][j]; } } } return p;}int** f(int** a, int n){ if(n < 1) return NULL; if(n == 1) return a; if(n%2 == 0){ return matrix_multi(f(a, n/2), f(a, n/2)); } else { return matrix_multi(matrix_multi(f(a, (n-1)/2), f(a, (n-1)/2)), a); } } int main(){ int ** a = new int *[2]; for (int i =0; i<2; i++){ a[i] = new int[2]; } a[0][0] = 1; a[0][1] = 1; a[1][0] = 1; a[1][1] = 0; printf("%d", *(*f(a, 10)+1)); printf("\n"); return 0; }
上面计算出来的结果都是55,即fibo(10)的结果
计算矩阵的乘法
一般而言矩阵的乘法需要三层for循环,这是一个n^3的算法。strassen提出了一个n^(log2(7))的算法,教授也讲了,这个我就不说了。
VLSI (超大规模集成电路)的布局
其实就是求完全二叉树怎么放占的矩形面积最小,要求每个树的顶点在点阵的点上。
最后面积是O(n),长宽各sqrt(n),做一个H布局。
这个我觉得纯属智力题,老师也没说怎么推导出来的。
- Divide and conquer algorithm
- Divide-and-Conquer
- 分治 Divide and Conquer
- divide-and-conquer
- algorithm:divide and conquer
- Divide and Conquer
- Divide and Conquer
- Divide and conquer
- divide and conquer
- Divide and Conquer
- [leetcode] Divide and Conquer
- Divide and Conquer
- Divide and Conquer
- Divide and conquer 总结
- leetcode-Divide and Conquer
- LeetCode--Divide and Conquer
- Divide and Conquer
- Divide-and-Conquer
- 文件操作和QStringList
- [学习小结]Hibernate的Helloworld
- git clone 远程分支
- SEO如何提高百度权重
- OpenCV+win7+VS2010环境搭建
- divide and conquer
- qt里button相关
- instancetype和id的区别
- 面试经验以及职位要求--Java开发(不知道是哪个学长的经验了)
- python 服务器 select 游戏
- 分页SQL走全表扫描导致TEMP耗尽
- C++无法解析的外部符号的3种可能
- Python Tkinter Hello,Tkinter
- NSString asscii格式(2进制) 转 utf8格式——解决iOS自己处理http socket数据,遇到Transfer-Encoding: chunked时