使用不同方法求解最大子序列之和问题

Posted jiahu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用不同方法求解最大子序列之和问题相关的知识,希望对你有一定的参考价值。

/*
    Solutions for the Maximum Subsequence Sum Problem
    四种方法,时间复杂度依次递减:O(N^3)、O(N^2)、O(N log(N))、O(N)
*/
#include<vector>
#include<algorithm>
#define CATCH_CONFIG_MAIN
#include"catch.hpp"

using namespace std;

//生成测试数据,第一个参数为生成的数组,第二个参数为正确结果
pair<vector<int>, int> create_test_data (int len = 99);

//穷举法,时间复杂度为O(n^3)
int max_sub_sum0 (const vector<int>& data)
{
    assert (data.size() > 0);
    int max_sum = data[0];
    
    for (int i = 0; i < data.size(); i++)
    {
        for (int j = i; j < data.size(); j++)
        {
            int this_sum = 0;
            
            for (int k = i; k <= j; k++) { this_sum += data[k]; }
            
            max_sum = max (this_sum, max_sum);
        }
    }
    
    return max_sum;
}

//优化max_sub_sum0,使得时间复杂度为O(n^2)
int max_sub_sum1 (const vector<int> &data)
{
    assert (data.size() > 0);
    int max_sum = data[0];
    
    for (int i = 0; i < data.size(); i++)
    {
        int this_sum = 0;
        
        for (int j = i; j < data.size(); j++)
        {
            this_sum += data[j];
            max_sum = max (max_sum, this_sum);
        }
    }
    
    return max_sum;
}

//使用递归算法,算法的时间复杂度为N*log(N)
int max_sub_sum2 (const vector<int> &data, int left, int right)
{
    if (left == right)
    {
        if (data[left] > 0) { return data[left]; }
        
        else { return 0; }
    }
    
    int center = (left + right) / 2;
    int left_max = max_sub_sum2 (data, left, center);
    int right_max = max_sub_sum2 (data, center + 1, right);
    int border_max_left = 0;
    int buf = 0;
    
    for (int i = center; i >= left; i--)
    {
        buf += data[i];
        border_max_left = max (border_max_left, buf);
    }
    
    int border_max_right = 0;
    buf = 0;
    
    for (int i = center + 1; i <= right; i++)
    {
        buf += data[i];
        border_max_right = max (border_max_right, buf);
    }
    
    return max (border_max_left + border_max_right, max (left_max, right_max));
}

//使用动态规划,使得时间复杂度为:O(N)
int max_sub_sum3 (const vector<int> &data)
{
    int max_sum = 0;
    int this_sum = 0;
    
    for (auto &x : data)
    {
        this_sum += x;
        max_sum = max (max_sum, this_sum);
        
        if (this_sum < 0)
        {
            this_sum = 0;
        }
    }
    
    return max_sum;
}

TEST_CASE ("test")
{
    srand (time (nullptr));
    
    for (int i = 0; i < 9; i++)
    {
        auto test = create_test_data (99 + (rand() % 100));
        REQUIRE (test.second == max_sub_sum0 (test.first));
        REQUIRE (test.second == max_sub_sum1 (test.first));
        REQUIRE (test.second == max_sub_sum2 (test.first, 0, test.first.size() - 1));
        REQUIRE (test.second == max_sub_sum3 (test.first));
    }
}

//使用Data Structures and Algorithm Analysis in C++ 书中的代码作为标准求解正确答案
int maxSubSum4 (const vector<int> & a)
{
    int maxSum = 0, thisSum = 0;
    
    for (int j = 0; j < a.size(); ++j)
    {
        thisSum += a[j];
        
        if (thisSum > maxSum)
        { maxSum = thisSum; }
        
        else
            if (thisSum < 0)
            { thisSum = 0; }
    }
    
    return maxSum;
}

pair<vector<int>, int> create_test_data (int len)
{
    assert (len > 0);
    vector<int> results (len);
    srand (time (nullptr));
    
    for (auto &e : results)
    {
        int rand_num = rand();
        int sign = 1;
        
        if ( (rand() % 1000) > 600) { sign = -1; }
        
        e = sign * rand_num;
    }
    
    //assert ([&results]()->bool {for (auto &x : results) { if (x < 0) return true; } return false; }());
    return make_pair (results, maxSubSum4 (results));
}

以上是关于使用不同方法求解最大子序列之和问题的主要内容,如果未能解决你的问题,请参考以下文章

hdu1003 Max Sum最大连续子序列之和

java 求最大子序列和问题递归求解报越界异常

动态规划求最大子序列之和以及序列号

返回一个二维整数数组最大子数组的和

返回一个二维整数数组中最大子数组的和

求解最大连续子序列和问题