个人笔记——数据结构与算法(1.3实例应用与分析)

1.3 实用应例:最大子序列

1.3.1 题目

给定N个整数的序列{A1 , A2 , ……,AN},求函数 的最大值,若值为负数,则放回0

1.3.1 暴力算法
1.3.1 方法1

思路:算出每个子序列的和

int fun1(int a[],int n){
     int ThisSum,MaxSum=0;
     for(int i=0;i<n;i++){ /*i是左端位置*/ 
         for(int j=n;j>i;j--){ /*j是右端位置*/ 
             ThisSum=0;
             for(int k=i;k<j;k++){
                 ThisSum+=a[k];/*从1~5,2~5,3~5,……*/
                 if(ThisSum>MaxSum) MaxSum=ThisSum;
             }
         }
     }
     if(MaxSum<0) MaxSum=0;
     return MaxSum;  
 }

缺点:每次都会再次计算前面计算过的子序列和

时间复杂度:因为三重循环,且每次循环均接近N

所以时间复杂度为: T\left ( N \right )=O\left (N ^{3} \right )

1.3.1 方法二(暴力优化)

思路:重新计算的部分省略

 int fun2(int a[],int n){
     int ThisSum,MaxSum=0;
     for(int i=0;i<n;i++){/*i是左端位置*/ 
         ThisSum=0;
         for(int j=i;j<n;j++){/*j是右端位置*/ 
             ThisSum+=a[j];/*从1~5,2~5,3~5,……*/
             if(ThisSum>MaxSum) MaxSum=ThisSum;
         }
         if(MaxSum<0) MaxSum=0;
     }
     return MaxSum;
 }

时间复杂度:两重循环,且每次循环均接近N

所以时间复杂度为T\left ( N \right )=O\left ( N^{2} \right )

1.3.1 分治(分而治之)

思路:

        分:将数据分为左右两块,再左右两边以此递归(再次分为左右两边),足够小,求出当前最大

         治:跨越边界,求出最大,从中间位置向两边扫描 三者相比较,求出最大的值

int cross_sum(int a[],int left,int right,int mid){
     if(left==right) return a[left];
     int leftsum=INT_MIN;/*int能找到的最小值*/
     int Thissum=0;
     for(int i=mid;i>left-1;i--){/*中点向左侧遍历,最大子序列和*/
         Thissum+=a[i];
         leftsum=max(leftsum,Thissum);
     }
     int rightsum=INT_MIN;
     Thissum=0;
     for(int i=mid+1;i<right+1;i++){/*中点向右侧遍历,最大子序列和*/
         Thissum+=a[i];
         rightsum=max(Thissum,rightsum);
     }
     return (leftsum+rightsum);
 }
 ​
 int fun3(int a[],int left,int right){
     if(left==right) return a[left];
     int LeftSum,RightSum,CrossSum;
     int mid=(left+right)/2;
     LeftSum=fun3(a,left,mid);/*确定左边的最大子序列*/
     RightSum=fun3(a,mid+1,right);/*确定右边最大子序列*/
     CrossSum=cross_sum(a,left,right,mid);/*跨越边界的子序列和*/
     return max(max(LeftSum,RightSum),CrossSum);
 }

程序运行过程:

时间复杂度:
T\left ( N \right )= 2T\left ( \frac{N}{2} \right )+cN ,T(1)=O(1)\\ =2\left [ 2T\left ( \frac{N}{2^{2}} \right )+c\frac{N}{2} \right ]+cN\\ =2^{k}O\left ( 1 \right )+ckN

其中乘以2^k,前得N,k为logN,以2为底的logN


所以T\left ( N \right )=O\left ( N \right )+O\left ( NlogN \right )

 相加取最大,时间复杂度为O\left ( NlogN \right )O(NlogN)

1.3.1 在线处理法

思路:当前子序列和为负数时,不会为后续子序列和提供价值,舍弃,保证当前答案的正确性

int fun(int a[],int n){
     int ThisSum=0,MaxSum=0;
     for(int i=0;i<n;i++){
         ThisSum+=a[i];
         if(ThisSum>MaxSum) MaxSum=ThisSum;
         else if(ThisSum<0) ThisSum=0;/*小于0无法为后面提供价值*/
     }
     return MaxSum;
 }

时间复杂度:一个for循环,循环里面的所有东西包括if—else 都是常数量级的复杂度
T\left ( N \right )=O\left ( N \right )
 

 第一个数字:-1 , 使得ThisSum=-1<0 , 没有价值,舍弃

 第二个数字:3 ,使得使得ThisSum=3>MaxSum , MaxSum=3

 第三个数字:-2,使得ThisSum=1<MaxSum , 不更新,MaxSum=3

 第四个数字:4,使得ThisSum=5>MaxSum , 更新 , MaxSum=5

以此类推,保证当前绝对正确

在线的意思是指每输入一个数据就即时处理,在任何一个地方中止输入,算法都能给出正确的、当前的解

1.3.1 运行时间

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值