zoukankan      html  css  js  c++  java
  • 算法设计--在数组中找求和最大的连续子串

    问题:输入具有n个整数的向量arr,输出向量的任意连续子向量和的最大值

    特殊情况(1、当向量都为正数时,为整个向量

         2、当向量都为负数时,为0,即空子串

        )

    1、O(n2)的算法 (循环对所有情况进行遍历)

     1 #include <stdio.h>
     2 #define max(a,b) ((a>b)?a:b)
     3 #define max3(a,b,c) ((a>b)?((a>c)?a:c):((b>c)?b:c))
     4 
     5 int find1(int arr[], int n){
     6     int i,j,sum,maxsofar;
     7     maxsofar = 0;
     8 
     9     for(i=0; i<n; i++){
    10         sum = 0;
    11         for(j=i; j<n; j++){
    12             sum += arr[j];
    13             maxsofar = max(sum, maxsofar);   
    14         }
    15     }
    16     return maxsofar;
    17 }

    其中有个小细节就是 注意sum(i, j-1) 和 sum(i, j)的关系,不要每次在求和的时候从头(i的位置)开始,那样会使复杂度变为O(n3)


    2、O(nlogn)算法

    基于分治原理的算法:首先将n的原问题划分为大小基本相等的两个子问题,我们分别称为a和b子问题,可以递归找出a和b问题的最大子向量,称为maxa 和 maxb。

    但他们两个之间的最大值不一定使我们求得n问题的最优解,还有一种可能是跨越a和b的边界,我们称之为c,c情况的最优解为maxc。

    那么问题变成了如何求解maxc?

    我们可以发现,maxc中在a的部分为a中包括a的右边界的最大值,maxc中在b的部分为b中包括b的左边界的最大值,因此可以在O(N)的时间内算出maxc

    因此得到T(N) = 2T(N/2) + O(N)

    推导得到T(N) = O(nlogn)

     1 int find2(int arr[], int s_p, int e_p){
     2     int m, sum, i, maxsofar, lmaxsofar, rmaxsofar;
     3     maxsofar = 0;
     4 
     5     if(s_p == e_p){
     6         return maxsofar;
     7     }
     8     else if(s_p == e_p){
     9         return max(arr[s_p],0);
    10     }
    11     else{
    12         m = (s_p + e_p) / 2;
    13 
    14         lmaxsofar = 0;
    15         sum = 0;
    16         for(i=m; i>=s_p; i--){
    17             sum += arr[i];
    18             lmaxsofar = max(sum, lmaxsofar);
    19         }
    20 
    21         rmaxsofar = 0;
    22         sum = 0;
    23         for(i=m+1; i<=e_p; i++){
    24             sum += arr[i];
    25             rmaxsofar = max(sum, rmaxsofar);
    26         }
    27 
    28         return max3(lmaxsofar+rmaxsofar,find2(arr, s_p, m), find2(arr, m+1, e_p));
    29     }
    30 }

    3、O(n)算法

    先上代码,代码非常简短,理解起来比较困难,但是执行效率非常高

     1 int find3(int arr[], int n){
     2     int i,maxsofar,maxendinghere;
     3     maxsofar = 0;
     4     maxendinghere = 0;
     5     
     6     for(i=0; i<n; i++){
     7         maxendinghere = max(maxendinghere + arr[i], 0);
     8         maxsofar = max(maxsofar, maxendinghere);
     9     }
    10 
    11     return maxsofar;
    12 }

    假设我们已经解决了x[0,n-1]的问题,利用分治算法的原理:前i个元素中,最大总和子数组要么在前i-1个元素中,要么其结束位置在i处。

    分析其结束为止在i处的情况,那么子向量中除去i处的元素组成的子向量一定是x[0,i-1]中结束位置为i-1的最大子向量。

    看代码中的关键变量为maxendinghere:在循环语句的第一个赋值语句之前,maxendinghere是结束位置为i-1的最大子向量的和;赋值语句将其修改为结束位置为i的最大子向量的和。若加上x[i]后结果依然为正值,则结束位置在i的最大子向量值就为maxendinghere+x[i],如果为负值,则重置为0。

  • 相关阅读:
    Shiro笔记(三)shiroFilter拦截器配置原则
    Shiro笔记(二)Shiro集成SpringMVC的环境配置
    Shiro笔记(一)Shiro整体介绍
    javaNIO的总结
    Redis的工作流程
    Nginx的配置安装和使用
    Linux下java开发环境配置总结
    php 基础知识 post 和get 两种传输方式的区别
    php 高级 多台web服务器共享session的方法
    php 基础知识 SESSION 和 COOKIE 的区别
  • 原文地址:https://www.cnblogs.com/lwyeah/p/8584122.html
Copyright © 2011-2022 走看看