P153
学习目标:
|
“基本操作”、渐进时间复杂度、O !“最大连续和”问题的各种算法及其时间复杂度分析 算法分析的优点和局限性,使用分析结果 !归并排序和逆序对统计的分治算法 快速选择和快速选择算法 !!二分查找算法,包括找上下界的算法 能用递归的方式思考和求解问题 !!二分法求解非线性方程 !!二分法把优化问题转化为判定问题 !贪心法的各类经典问题 |
枚举、回溯等暴力方法:较低效。越通用,越不能挖掘问题的特殊性
8.1算法分析初步
在编程之前估计时空开销(如果又复杂又慢,就不要急着写出来)
渐进时间复杂度
例8-1:长度n序列,求最大连续和。
解:
#include<stdio.h>
//#define LOCAL
#define N 3
int main(){
#ifdef LOCAL
freopen("data.in","r",stdin);
freopen("data.out","w",stdout);
#endif
int A[N]={-1,1,2};
int max=A[0];
int sum=0;
int i,j;
for(i=0;i<N;i++){
//sum清零,从i加到j,比较
sum=0;
for(j=i;j<N;j++){
sum+=A[j];//也是递推思想
if(sum>max)max=sum;
}
}
printf("max:%d",max);
return 0;
}
Max初值为A[0]最保险,初值为0在所有值为负时可能出现问题
基本操作的数量,排除机器影响,衡量算法操作的次数。
渐进时间复杂度:基本操作的数量用输入规模表达式,保留最大项忽略系数。衡量操作数随规模的增长情况
输入规模为n时:
上界分析
上界分析:所有最坏情况同时取到
渐进时间复杂度推导:3重循环,每层最坏n次,总运算次数<=n^3(数量级一致,紧上界)
分治法
步骤:划分子问题,递归解决子问题,合并子问题得到解
把元素分成两半,分别求最佳序列,求出起点位于左半,终点位于右半的最大序列,并和子问题的最优解比较
关键在于合并,先寻找最佳起点,在寻找最佳终点
区间分割、取平均数技巧
取最大值符号>?经过尝试,编译错误,这里用函数greater代替
#include<stdio.h>
//#define LOCAL
#define N 3
int greater(int a,int b){
return a>b?a:b;
}
int maxsum(int* A,int x,int y){//返回[x,y)区间的最大序列和
int max; //分段后局部最大值
int m;//分界点
int v,i;
int L,R;//从分界点外扩左右两段全局最大值
if(y-x<=1)return A[x];//只有一个元素时直接返回
m=x+(y-x)/2;//确定分界点
// max=maxsum(A,x,m)>?maxsum(A,m,y);//递归,分段后局部最大值
max=greater(maxsum(A,x,m),maxsum(A,m,y)) ;
//求拼接和
v=0;L=A[m-1];
// for(i=m-1;i>=x;i--) L>?=v+=A[i];//分界点往外全局最大值
for(i=m-1;i>=x;i--){
// L=greater(L,v+=A[i]);
v+=A[i];
L=greater(L,v);
}
v=0;R=A[m];
// for(i=m;i<y;i++) R>?=v+=A[i];//分界点往外全局最大值
for(i=m;i<y;i++) R=greater(R,v+=A[i]);
// return max >?(L+R);//局部最优与全局最优比较
return greater(max,(L+R));
}
int main(){
#ifdef LOCAL
freopen("data.in","r",stdin);
freopen("data.out","w",stdout);
#endif
int A[N]={-1,1,2};
printf("max:%d",maxsum(A,0,3));
return 0;
}
另一个细节-计算分界点:
计算机是朝0取整(只取整数部分),而不是向下取整(负数时不同)
用x+(y-x)/2代替(x+y)/2可以达到向下取整的效果
法四:
N、nlog2N规模大,随速度增长快
有效算法:渐进时间复杂度为多项式(多项式时间算法)
指数时间算法:n!、2^n