数据结构与算法分析第二章读书笔记
来源:互联网 发布:2016中国海外并购数据 编辑:程序博客网 时间:2024/04/29 08:32
这本书第二章引发了一个问题,求最大子序列和,并给出了四种解题算法进行对比。问题描述:给定一个数组,求出该数组的最大子序列。
算法1
暴力搜索:即找出所有的子序列,并对其求和来与最大值比较。时间复杂度为O(n3);
int maxSum1(int sum[],int start,int end){ int i,j,k; int maxSum = 0; int tmpSum; for(i = start;i<end;i++){ for(j = i;j<end;j++){ tmpSum = 0; for(k = i;k<j;k++) tmpSum+=sum[k]; if(tmpSum>maxSum) maxSum = tmpSum; } } return maxSum;}
算法2
对算法1进行优化,发现,在最内层中,有大量的工作是在做重复的事情,因此将其优化为如下:时间复杂度为O(n2)
int maxSum2(int sum[],int start,int end){ int i,j,k; int maxSum = 0; int tmpSum; for(i = start;i<end;i++){ tmpSum = 0; for(j = i;j<end;j++){ tmpSum+=sum[j]; if(tmpSum>maxSum) maxSum = tmpSum; } } return maxSum;}
算法3
使用二分法,将原来的规模变成子问题的一半,然后再去求解。运行时间为T(N) = 2*T(N/2)+O(N);时间复杂度为O(NlogN);
int maxSum3(int sum[],int start,int end){ int leftMaxSum,rightMaxSum; int leftBorderSum,rightBorderSum; int leftMaxSubSum,rightMaxSubSum; if(end-start==1){ if(sum[start]>0) return sum[start]; else return 0; } int mid = (start+end)/2; leftMaxSum = maxSum3(sum,start,mid); rightMaxSum = maxSum3(sum,mid,end); //mid leftMaxSubSum = 0;rightMaxSubSum = 0; leftBorderSum = 0;rightBorderSum = 0; int tmp = mid; while(tmp>=start){ leftBorderSum+=sum[tmp--]; if(leftBorderSum>leftMaxSubSum) leftMaxSubSum = leftBorderSum; } tmp = mid+1; while(tmp<end){ rightBorderSum+=sum[tmp++]; if(rightBorderSum>rightMaxSubSum) rightMaxSubSum = rightBorderSum; } int midSum = leftMaxSubSum+rightMaxSubSum; //取三者最大值 int tmpSum = leftMaxSum>rightMaxSum?leftMaxSum:rightMaxSum; return tmpSum>midSum?tmpSum:midSum;}
算法4
我最多想到算法3,算法4是无论如何都没想到的,算法4的思想就是类似于一个数据流,然后原来的问题变成了从何处截流。当某处的值(或某处以前的值)为负数时,我肯定不会希望将这部分加入到子序列中(会拉低最大值)只有当子序列和非负时,继续下去,然后与最大值比对,看看是否超过最大值。
int maxSum4(int sum[],int start,int end){ int i; int tmpSum = 0; int maxSum = 0; for(i = start;i<end;i++){ tmpSum+=sum[i]; if(tmpSum>maxSum) maxSum = tmpSum; if(tmpSum<0) tmpSum = 0; } return maxSum;}
果然是很神奇的。
最后还有几个很有意思的结论,很希望与大家分享:
我在进行算法分析时,最头痛的就是分析log,不知道怎么计算得来。上面提到的二分法,时间复杂度为O(nlogn)。书上对对数常见的规律,归纳如下:
1、如果一个算法用常数时间O(1)将问题大小削减为其一部分(典型的1/2),然后此问题的时间复杂度为O(logn).
2、如果使用常数时间将问题大小减少一个常数(如1)则时间复杂度为O(n).
有几种典型的O(logn)的算法例子。
1、对分查找:对于一个有序数组,对数组查找某个元素,若找到,返回下标,若没有返回-1;
int binarySearch(ElementType A[],Element x,int N){ int low=0,high=N-1; int mid; while(low<=high){ mid = (low+high)/2; if(A[mid]==x) return mid; else if(A[mid]>x){ high= mid-1; }else{ low = mid+1; } } return -1;}
2、欧几里得算法
欧几里得算法用于求解两个数的最大公约数,利用的是公式gcd(a,b) = gcd(b,a%b).
代码如下:
int gcd(int m,int n){ int tmp; while(n>0){ tmp = m%n; m = n; n = tmp; } return m;}
对于这道题,我们也许可以模糊的知道大概是log级的算法,但是如何证明却实在是很困难。这里面的时间复杂度等同于计算循环的次数。
定理1:如果M>N,则M mod N 《M/2;
证明:若N<=M/2,则余数一定小于N,则M mod N《M/2; 若N》M/2,M mod N = M-N 《M/2;证毕;
由上述定理可知:gcd(m,n)=gcd(n,m%n)=gcd(m%n,n%(m%n);可见,只要2次gcd操作,就可以将n降为原来的一半,因此欧几里得算法时间复杂度确实为O(logn)
3、幂运算
处理一个整数的幂,计算X^N最直接的算法计算直接自乘,但是时间复杂度为O(N),这里可以优化的地方在于,可以减少多次重复计算量。比如,X^N = X^(N/2) * X^(N/2);而计算出第一个来之后,第二个直接相乘而不必再重复计算。
long int pow(int x,unsigned int N){ if(N==1) return X; if(N==0) return 1; if(N%2==0) return pow(x*x,N/2); else return pow(x*x,(N-1)/2)*x;}
- 数据结构与算法分析第二章读书笔记
- 数据结构与算法(C语言) 第二章 算法分析 读书笔记
- 数据结构与算法分析 第二章
- 读书笔记-《大话数据结构》第二章算法
- 大话数据结构 第二章 算法(读书笔记)
- 《数据结构与算法分析》笔记------第二章、对分查找
- 数据结构与算法分析学习笔记---第二章
- 数据结构与算法分析第二章12题
- 【数据结构与算法分析】第一章、第二章总结
- 一元函数 第二章 数据结构与算法分析 张琨
- 《数据结构与算法分析--c语言描述》之第二章:算法分析
- 数据结构与算法设计(读书笔记):2.算法分析
- 数据结构思维 第二章 算法分析
- 大话数据结构读书笔记——第二章 算法
- 【数据结构与算法分析】《算法竞赛入门经典》第二章 示例及答案
- 《数据结构与算法分析》读书笔记——hash表
- 《数据结构与算法分析》读书笔记——排序
- 《数据结构与算法分析:c语言描述》读书笔记
- Java4Android-子类实例化过程
- [Windows驱动开发](二)基础知识——数据结构
- hdu5293 Tree chain problem 树形dp+线段树
- 一篇很全面的freemarker教程
- OFBiz + Opentaps 目录管理 一. 基本概念
- 数据结构与算法分析第二章读书笔记
- Highcharts插件常见问题及解决办法
- 浅分析Oracle语句优化规则
- 设立sql语句在控制台的输出
- Android开发实践之判断应用前后台
- 【iOS开发之Objective-C】初始化对象
- Python学习记录概述
- hihocoder 1033 交错和 数位DP
- 新标准c++程序设计教程chapter2_2015.7.21