1. 程式人生 > >使用不同方法求解最大子序列之和問題

使用不同方法求解最大子序列之和問題

struct 一個 遞歸算法 def als main 復雜 mar false

/*
    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));
}

使用不同方法求解最大子序列之和問題