zoukankan      html  css  js  c++  java
  • 最大连续子数组以及拓展

    问题描述:给定一个整数数组,数组中可能有正数、负数和零。数组中连续的一个或者多个正数组成一个子数组,每个子数组都有一个和。求所有子数组的和的最大值。例如,若果输入的数组为{1,-2,3,,10,-4,7,2,-5},和最大的子数组为{3,10,-4,7,2},应输出该子数组的和18。

    解题方法一:蛮力枚举

      用三个for循环三层遍历,求出数组中每一个子数组的和,最终求出这些子数组和最大的一个值。

    参考代码:

    #include <bits/stdc++.h>
    
    using namespace std;
    
    int MaxSubArray( int *a, int n )
    {
        int maxSum = a[0];
        int currSum = 0;
        for( int i = 0 ; i < n ; i ++ )
        {
            for( int j = i ; j < n ; j ++ )
            {
                for( int k = i ; k <= j ; k ++ )
                {
                    currSum +=a[k] ;
                }
                if( currSum > maxSum )
                {
                    maxSum = currSum ;
                }
                currSum = 0;
            }
        }
        return maxSum;
    }
    
    int main()
    {
        int a[8]={1,-2,3,10,-4,7,2,-5};
        cout<<MaxSubArray(a,8);
    }

    GCC运行结果:

    该方法的时间复杂度为O(n^3)

    解题方法二:动态规划

      事实上,可以令currSum是以当前元素结尾的最大连续子数组的和,maxSum是全局的最大子数组的和,当往后扫描时,对第j个元素有两种选择,要么放入前面找到的子数组,要么作为新的子数组的第一个元素:如果currSum>0,则令currSum加上a[j],如果currsum<0,则currSum被置为当前元素,即currSum=a[j]。

      这相当于,如果设currSum(j)是以j结尾的最大连续子数组的和,那么currSum(j)=max{0,currsum[j-1]}+a[j]。如果maxSum<currSum,则更新maxSum=currSum;否则maxSum保持原值,不更新。

      举个例子,对于输入数组为{1,-2,3,10,-4,7,2,-5},那么currSum和maxSum的变化分别为:

    currSum: 0 -> 1 -> -1 -> 3 -> 13 -> 9 -> 16 -> 18 -> 13

    maxSum:  0 -> 1 -> 1 -> 3 -> 13 -> 13 -> 16 -> 18 -> 18

    参考代码:

    #include <bits/stdc++.h>
    
    using namespace std;
    
    int MaxSubArray( int *a , int n )
    {
        int currSum = 0;
        int maxSum = a[0];
        for( int j = 0 ; j < n ; j ++ )
        {
            if( currSum >= 0 )
            {
                currSum += a[j];
            }
            else
            {
                currSum = a[j];
            }
            if( currSum > maxSum )
            {
                maxSum = currSum;
            }
        }
        return maxSum;
    }
    int main()
    {
        int a[8]={1,-2,3,10,-4,7,2,-5};
        cout<<MaxSubArray(a,8);
    }

    GCC运行结果:

    该方法从前向后扫描数组一遍,因此该方法的时间复杂度为O(n)。

    问题变形:

    (1)如果要求出最大连续子数组的和,同时要求输出所求子数组的开始位置和结束位置呢?

      解答:在解题方法一二中只需要设置开始和结束位置,每次调整数值即可。

     解题方法一:

    #include <bits/stdc++.h>
    
    using namespace std;
    
    int MaxSubArray( int *a, int n )
    {
        int maxSum = a[0];
        int currSum = 0;
        int i,j,k;
        int start = 0;
        int over = 0;
        for(i = 0 ; i < n ; i ++ )
        {
            for( j = i ; j < n ; j ++ )
            {
                for( k = i ; k <= j ; k ++ )
                {
                    currSum +=a[k] ;
                }
                if( currSum > maxSum )
                {
                    start = j;
                    over = k;
                    maxSum = currSum ;
                }
                currSum = 0;
            }
        }
         cout<<"maxSum = "<<maxSum<<" start = "<<start+1<<" over = "<<over+1<<endl;
        return maxSum;
    }
    
    int main()
    {
        int a[8]={1,-2,3,10,-4,7,2,-5};
        cout<<MaxSubArray(a,8);
    }
    View Code

     解题方法二:

    #include <bits/stdc++.h>
    
    using namespace std;
    int MaxSubArray( int *a , int n )
    {
        int currSum = 0;
        int maxSum = a[0];
        int start = 0;
        int over = 0;
        for( int j = 0 ; j < n ; j ++ )
        {
            if( currSum >= 0 )
            {
                over = j;
                currSum += a[j];
            }
            else
            {
                start = j ;
                currSum = a[j];
            }
            if( currSum > maxSum )
            {
                maxSum = currSum;
            }
        }
        cout<<"maxSum = "<<maxSum<<" start = "<<start+1<<" over = "<<over+1<<endl;
        return maxSum;
    }
    int main()
    {
        int a[8]={1,-2,3,10,-4,7,2,-5};
        int start ,over ;
        MaxSubArray(a,8);
    }
    View Code

    (2)如果要求出最大子数组的和,但不要求子数组是连续的呢?

     解答:只需要遍历数组,如果该数大于0,则sumMAX加上该数。时间复杂度为O(n)

    (3)如果数组是二维数组,同样要求出最大连续子数组的和呢?

    解答:将a[0][] a[1][0]...a[n][]分别使用一位数组的方法求解出每个单位数组的最大值,对着n个最大的和进行快速排序找到最大的和

    (4)如果是要求出连续子数组的最大乘积呢?

  • 相关阅读:
    Ember.js 入门指南——计算属性(compute properties)
    Ember.js 入门指南——扩展(reopen)
    Ember.js 入门指南——类的定义、初始化、继承
    Ember.js 入门指南——目录
    Ember.js 入门指南——{{action}} 助手
    ubuntu按转jdk
    ubuntu设置电脑作为wifi热点
    一步完成linux安装jdk
    GStreamer基础教程13
    GStreamer基础教程12
  • 原文地址:https://www.cnblogs.com/zpfbuaa/p/5348298.html
Copyright © 2011-2022 走看看