zoukankan      html  css  js  c++  java
  • 数组中子数组之和最大问题

      问题描述:给定一个包含N个元素的数据A(A[0], A[1], A[2]...A[N-1]),这个数组自然有很多子数组,那么,这些子数组之和的最大值是什么?

      Example: 数组[1, -2, 3, 5, -3, 2],最大的子数据是[3, 5],和为8。

      解法一:穷举法

      最直接,也是最简单的方法,穷举子数组A[i:j]的和,找出一个最大的,算法的时间复杂度O(N2),算法的代码如下:

    #include <iostream>
    #include <climits>
    
    using namespace std;
    
    int max_sub_sum(const int* A, int n)
    {
        int max_sum = INT_MIN;
    
        for (int i = 0; i < n; i++)
        {
            int sub_sum = 0;
            for (int j = i; j < n; j++)
            {
                sub_sum += A[j];                //sum(i,j)
                if ( max_sum < sub_sum)
                {
                    max_sum = sub_sum;
                }
            }
        }
    
        return max_sum;
    
    }
    
    int main()
    {
        int A[] = {1, -2, 3, 5, -3, 2};
        int max_sum = max_sub_sum(A, sizeof(A) / sizeof(int));
        cout<<"max sub sum:"<<max_sum<<endl;
        system("pause");
        return 0;
    }

      解法二:分治法

      将数组分成两个子数组:A[0:n/2]和A[n/2 + 1, n]那么最大的组数据之和,必然出现在以下三种情况;

      1)最大子段与A[0:n/2]重合;

      2)最大子段与A[n/2 + 1, n]重合

      3)最大子段夸过A[0:n/2]和A[n/2 + 1, n-1]两段。

      对于1)、2)两种情况可以递归解决,而对于第三种情况,我们只要找到A[0:n/2]以n/2为终点最大和,A[n/2 + 1, n-1]以n/2 + 1为起点的最大和,两种相加即可。

    算法的时间复杂度为O(NlogN),代码如下:

    #include <iostream>
    #include <climits>
    
    using namespace std;
    
    int max_sub_sum(int* A, int i, int j)
    {
        if (i == j)
        {
            return A[i];
        }
    
        int mid = (i + j) / 2;
        int max_sum = max(max_sub_sum(A, i, mid), max_sub_sum(A, mid+1, j));
        
        int left_mid_max_sum = INT_MIN;
        int mid_sum = 0;
        for (int k =mid; k >= i; k--)
        {
            mid_sum += A[k];
            if (left_mid_max_sum < mid_sum)
            {
                left_mid_max_sum = mid_sum;
            }
        }
    
        int right_mid_max_sum = INT_MIN;
        mid_sum = 0;
        for (int k = mid+1; k <= j; k++)
        {
            mid_sum += A[k];
            if (right_mid_max_sum < mid_sum)
            {
                right_mid_max_sum = mid_sum;
            }
    
        }
    
        max_sum = max(max_sum, left_mid_max_sum + right_mid_max_sum);
    
        return max_sum;
    
    }
    
    int main()
    {
        int A[] = {1, -2, 3, 5, -3, 2};
        int max_sum = max_sub_sum(A, 0, (sizeof(A) / sizeof(int)) -1);
        cout<<"max sub sum:"<<max_sum<<endl;
        system("pause");
        return 0;
    }

      解法三:动态规划

      动态规划问题依赖于两个基本因素:1)最优子结构;2)重叠结构。首先定义两个量All(i)和Start(i),All(i)表示从A[i:n-1]数组中最大的子段和,Start(i)则表示了以下表i作为起始位置的最大子段和,那么该问题的最优的递归表达式:

      All(i) = max(All(i+1), start(i))

      这个公式表示,All(i)取:从i下标开始的字段数组start(i),从i+1开始的最大字段和All(i+1)之间的最大值, start(i)的定义如下:

      start(i) = max(A[i], A[i] + start(i+1))

    该解法的代码如下:

    #include <iostream>
    #include <climits>
    
    using namespace std;
    
    int max_sub_sum(int* A, int n)
    {
        int all = A[n-1];
        int start = A[n -1];
    
        for (int i = n -2; i >= 0; i--)
        {
            start = max(A[i], A[i] + start);        //start(i) = max(A[i], start(i+1))
            all = max(all, start);
        }
    
        return all;
    }
    
    int main()
    {
        int A[] = {1, -2, 3, 5, -3, 2};
        int max_sum = max_sub_sum(A, sizeof(A) / sizeof(int));
        cout<<"max sub sum:"<<max_sum<<endl;
        system("pause");
        return 0;
    }

      最后一种方法是淳朴的迭代算法。

      迭代算法看起来简单,但是这个问题但有着极其惊人的疗效:1)用变量per_sum保存当前以i-1作为结束下标的字段数组和,如果per_sum小于0(前面的部分起到了“负面”作用,需要舍弃),从下标i开始从新字段数组,于此同时,不断比较每次字段数组的最大值,当迭代结束是,便会得到字段数组的组大和。 

    #include <iostream>
    #include <climits>
    
    using namespace std;
    
    int max_sub_sum(int* A, int n)
    {
        int max_sum = INT_MIN;
        int sum = 0;
    
        for (int i = 0; i < n; i++)
        {
            if (sum < 0)                //前面的元素提到了负面作用,需要舍弃
            {
                sum = A[i];
            }
            else
            {
                sum += A[i];            //前面的元素提到了正面作用,需要保留
            }
            if (sum > max_sum)
            {
                max_sum = sum;
            }
        }
    
        return max_sum;
    
    }
    int main()
    {
        int A[] = {1, -2, 3, 5, -3, 2};
        int max_sum = max_sub_sum(A, sizeof(A) / sizeof(int));
        cout<<"max sub sum:"<<max_sum<<endl;
        system("pause");
        return 0;
    }

     

  • 相关阅读:
    Redis
    多线程相关
    selenium操作浏览器的基本方法
    selenium之 webdriver与三大浏览器版本映射表(更新至v2.29)
    selenium安装及官方文档
    Python(3)_python对Json进行操作
    python类中的self参数和cls参数
    python3中shuffle函数
    Python3中assert断言
    python2和python3中range的区别
  • 原文地址:https://www.cnblogs.com/wangbogong/p/3266748.html
Copyright © 2011-2022 走看看