算法导论--最大子数组问题

看了若干篇的博客,终于想明白了,尽量用最通俗易懂的方法讲解这个问题。


暴力解决:

   时间复杂度O(n^3)

       int sum = 0;

       for(int i = 0; i < n; ++i)

       {

              for(int j = i; j < n; ++j)

              {

                      for(int k = 0; k <= j; ++k)

                            sum += A[k];

                      if(sum > max)

                            max = sum;

                      sum = 0;//注意此处必须置为0,防止重复相加

              }

       }

       return max;

   时间复杂度O(n^2)

       int sum;

       for(int i = 0; i < n; ++i)

       {

             sum = 0;//这两种方式的区别应该是显而易见的!,不再赘述。

              for(int j = i; j < n; ++j)

              {

                      sum += A[j];

                      if(sum > max)

                            max = sum;

              }

       }


分治策略(递归):时间复杂度O(nlogn)

int find_max_sub(vector<int>& vi, int start,int end,int &left,int &right)
{
    if(start<=end)
    {
        int mid=start+(end-start)/2;
        int lfv,rhv;
        int ll,lr;
        int rl,rr;
        lfv=find_max_sub(vi,start,mid-1,ll,lr);
        rhv=find_max_sub(vi,mid+1,end,rl,rr);
    
        //找到包含vi[mid]的最大子数组
        int i=0;
 
        int temp=vi[mid];
        int l_index=mid;
        int l_value=vi[mid];
        for(i = mid - 1; i >= start; i--)
        {
            l_value += vi[i];
            l_index = l_value > temp ? i : l_index;
            temp = l_value > temp ? l_value : temp;
        }        
        l_value = temp;
 
        temp=vi[mid];
        int r_index=mid;
        int r_value=vi[mid];
        for(i = mid + 1; i <= end; i++)
        {
            r_value += vi[i];
            r_index = r_value > temp ? i : r_index;
            temp = r_value > temp ? r_value : temp;
        }
        r_value = temp;
 
        temp = l_value + r_value - vi[mid];
        return  
        (lfv < rhv ? (rhv < temp ? (left = l_index, right = r_index, temp) : (left = rl,right = rr, rhv))  
        : (lfv < temp ? (left = l_index, right = r_index, temp) : (left = ll, right = lr, lfv)));//返回三者中的最大值
    }
    else
        return INT_MIN;
}

第三种方法,时间复杂度O(n);(难点)

       假设数组为A[0,...,n-1],包含n个元素;初始化sum=0,从左到右遍历数组,sum=sum+A[i];现在,假设数组中一定会存在j,使得如下两个不等式成立:sum > 0 && sum + A[j] < 0(此处的j为第一次遇到这种情况),到此时为止,令sum=0;按照上述规则把所有的j找到,那么数组就被分为了如下情况:A[1....j1.....j2....j3.....n-1],最大子数组一定处于某个部分之中,不会横跨两个部分,也就是说肯定不会包含下标j(代指j1,j2,j3,....)。假如不存在这样的j,那么可以将数组看做一个整体处理;代码如下,接合代码思考这个问题:

int FIND_MAXIMUN_SUBARRAY(int* A,int n)

{

     int sum = 0;

     int max = -INF;//INF表示最大的整数

     for(int i = 0; i < n; ++i)

     {

           sum += A[i];                //      if(sum < 0)

           if(sum < 0)                   //            sum = A[i];

                 sum = 0;                 //    else   sum += A[i];后边的代码能够处理全是负数的情况

          if(max < sum)             

                 max = sum;

     }

     return max;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值