最大子数组问题

作者: 九十九度中 | 来源:发表于2017-05-08 09:49 被阅读80次

看算法导论,其中第四章讲到了最大子数组问题,书上讲了暴力求解和分而治之两种方法,实现了这两种方法后,看课后习题说,其实还有另一种线性时间的解,就又自己动手写了起来。
底下,是对这三种解法的一个总结(代码也不难,我就废话不多,直接上代码了)。

暴力求解(O(n^2))
#include <iostream>
#include <vector>
using namespace std;
typedef struct {
    int left;
    int right;
    int sum;
} ans_tuple;
ans_tuple find_max_subarray_violence(vector<int>& vec);
int main()
{
    int n;
    cin >> n;
    vector<int> vec;
    int elem;
    for (int i = 0; i < n; ++i) {
        cin >> elem;
        vec.push_back(elem);
    }
    ans_tuple a_t = find_max_subarray_violence(vec);
    cout << a_t.sum << " " << a_t.left << " " << a_t.right << endl;
    system("pause");
}

ans_tuple find_max_subarray_violence(vector<int>& vec) {
    int max_sum, this_sum;
    max_sum = this_sum = 0;
    int right, left;
    right = left = 0;
    vector<int> v_left;
    for (int index = 0; index < vec.size(); ++index) {
        this_sum = 0;
        for (int j = index; j < vec.size(); ++j) {
            this_sum += vec[j];
            if (this_sum > max_sum) {
                max_sum = this_sum;
                v_left.push_back(index);
                right = j;
            }
        }
    }
    if (max_sum == 0) {
        for (int j = 0; j < vec.size(); ++j) {
            if (vec[j] == 0) {
                return{ vec[j],vec[j],0 };
            }
        }
        return{ 0,vec.size() - 1,0 };
    }
    return{ v_left.size()-1,right,max_sum };
}
分而治之(O(nlgn))
#include <iostream>
#include <vector>
using namespace std;
typedef struct {
    int left;
    int right;
    int sum;
} ans_tuple;
ans_tuple find_crossing_subarray(int A[], int low, int mid, int high);
ans_tuple find_max_subarray_conquer(int A[], int low, int high);
ans_tuple max_ans(ans_tuple &left_ans, ans_tuple &right_ans, ans_tuple& cross_ans);
int main()
{
    int n;
    cin >> n;
    int A[10000] = {};
    for (int i = 0; i < n; ++i) {
        cin >> A[i];
    }
    ans_tuple a_t = find_max_subarray_conquer(A,0,n-1);
    cout << a_t.sum << " " << a_t.left << " " << a_t.right << endl;
    system("pause");
}
ans_tuple find_crossing_subarray(int A[],int low,int mid,int high) {
    int left_sum, right_sum, sum;
    left_sum = right_sum = sum = 0;
    int left,right;
    left = right = mid;
    for (int i = mid; i >= low; --i) {
        sum += A[i];
        if (sum > left_sum) {
            left_sum = sum;
            left = i;
        }
    }
    sum = 0;
    for(int j = mid + 1; j<=high;++j){
        sum += A[j];
        if (sum > right_sum) {
            right_sum = sum;
            right = j;
        }
    }
    return{ left,right,left_sum + right_sum };
}
ans_tuple find_max_subarray_conquer(int A[], int low, int high) {
    int mid;
    if (high == low) {
        return{ low,high,A[low] };
    }
    else {
        mid = (low + high) / 2;
    }
    ans_tuple left_ans = find_max_subarray_conquer(A, low, mid);
    ans_tuple right_ans = find_max_subarray_conquer(A, mid + 1, high);
    ans_tuple cross_ans = find_crossing_subarray(A, low, mid, high);
    ans_tuple ans = max_ans(left_ans, right_ans, cross_ans);
    if (ans.sum == 0) {
        for (int j = 0; j <= high; ++j) {
            if (A[j] == 0) {
                return{ j,j,0 };
            }
        }
        return{ 0,high,0 };
    }
    return ans;
    
}
ans_tuple max_ans(ans_tuple &left_ans, ans_tuple &right_ans, ans_tuple& cross_ans) {
    if (left_ans.sum >= right_ans.sum && left_ans.sum >= cross_ans.sum) {
        return left_ans;
    }
    else if (right_ans.sum >= left_ans.sum && right_ans.sum >= cross_ans.sum) {
        return right_ans;
    }
    else return cross_ans;
}
线性时间解(O(n))
#include <iostream>
#include <vector>
using namespace std;
typedef struct {
    int left;
    int right;
    int sum;
} ans_tuple;

ans_tuple find_max_subarray_linear(vector<int>& vec) {
    int this_sum, max_sum;
    this_sum = max_sum = 0;
    int left, right;
    right = left = 0;
    vector<int> v_left;
    v_left.push_back(0);
    for (int i = 0; i < vec.size(); ++i) {
        this_sum += vec[i];
        if (this_sum > max_sum) {
            max_sum = this_sum;
            right = i;
        }
        else if (this_sum < 0) {
            this_sum = 0;
            if (i < vec.size() - 1) {
                v_left.push_back(i + 1);
            }
        }
    }
    if (max_sum == 0) {
        for (int j = 0; j < vec.size(); ++j) {
            if (vec[j] == 0) {
                return{ j,j,0 };
            }
        }
        return{ 0,vec.size()-1,0 };
    }
    for (int i = v_left.size()-1; i >= 0; --i) {
        if (v_left[i] <= right) {
            left = v_left[i];
            break;
        }
    }
        return{ left,right,max_sum };
}
int main()
{
    int n;
    cin >> n;
    vector<int> vec;
    int elem;
    for (int i = 0; i < n; ++i) {
        cin >> elem;
        vec.push_back(elem);
    }
    ans_tuple a_t = find_max_subarray_linear(vec);
    cout << a_t.sum << " " << a_t.left << " " << a_t.right << endl;
    system("pause");
}

相关文章

  • Leetcode-Medium 152. Maximum Pro

    题目描述 给定一个整数数组nums(有正有负),求最大子数组乘积 思路 求最大子数组乘积问题是求最大子数组之和演变...

  • 10《算法入门教程》分治算法之最大子数组问题

    1. 前言 本节内容是分治算法系列之一:最大子数组问题,主要讲解了什么是最大子数组问题,如何利用分治算法解决最大子...

  • 动态规划

    求最大子数组,最大子乘积

  • 分治算法解最大子序列和问题

    最大子序列和问题 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最...

  • 最大子数组问题

    看算法导论,其中第四章讲到了最大子数组问题,书上讲了暴力求解和分而治之两种方法,实现了这两种方法后,看课后习题说,...

  • 最大子数组问题

    Maximum Subarray 由于简书不支持latex语法,所以可以到下面的作业部落去看。https://ww...

  • 最大子数组问题

    最近在看算法导论,看到计算最大子数组问题,于是写了一个iOS版本的。 利用分治策略,逐层寻找 最大子数组存在三种情...

  • 最大子数组问题

    问题描述 一个只包含正负数的数组,求出连续元素之和最大的子数组。 解决1:暴力求解方法 尝试每个元素的组合,最终选...

  • LeetCode-152-乘积最大子数组

    LeetCode-152-乘积最大子数组 152. 乘积最大子数组[https://leetcode-cn.com...

  • 动态规划法(八)最大子数组问题(maximum subarray

    问题简介   本文将介绍计算机算法中的经典问题——最大子数组问题(maximum subarray problem...

网友评论

    本文标题:最大子数组问题

    本文链接:https://www.haomeiwen.com/subject/nfkmtxtx.html