多种姿势求解最大连续子数组

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lishang6257/article/details/83001394

最大连续子数组

问题描述

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和以及最大自数字。


样例 :13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7
输出 : 7 10 43


问题分析

本题并不复杂,这里以三种方法本别求解,按时间复杂度递减排列。

  1. o ( n 2 ) o(n^2)
    最简单的暴力求解所有连续的子数组的和,然后求最大值;
  2. o ( n l o g n ) o(nlogn)
    按算法导论中分治策略,可以将时间复杂度下降;同时动态规划也可以达到这个目的,不过中途也许借助两分查找降低时间复杂度。
  3. o ( n ) o(n)
    这个方法很巧妙。最开始一直陷入在 o ( n l o g n ) o(nlogn) 的时间复杂度中无法出来,一直在考虑用空间换取时间的方法降低时间复杂度,但是一直找不到很好的方法。后来看到有些用 o ( n ) o(n) 时间复杂度的样例,存在一些问题,后来问了下前辈才知道了方法,但是仍然不是知道用到了何种理论知道得出的,只给出求解方案了。

问题求解

方法一 :分治思想求解

result find_cross_max(vector<int>&a,int low,int high){
    int mid = (high + low)/2;
    int sumR = -1000,sumL = -1000;//-INF,这里假设是1000
    int R = 0,L = 0;
    int sum = 0;
    for(int i = mid;i >= low;i --){
        sum += a[i];
        if(sum > sumL){
            sumL = sum;L = i;
        }
    }
    sum = 0;
    for(int i = mid + 1;i <= high;i ++){
        sum += a[i];
        if(sum > sumR){
            sumR = sum;R = i;
        }
    }
    return result(L,R,sumR+sumL);
}

result resolve1(vector<int>&a ,int low,int high)
{
    if(low == high) return result(low,high,a[low]);
    //分治
    int mid = (high + low)/2;
    result r1 = resolve1(a,low,mid);
    result r2 = resolve1(a,mid+1,high);
    //跨越两者的数据
    result M = find_cross_max(a,low,high);
    return Max(r1,r2,M);
}

方法二:暴力求解

result resolve2(vector<int>&a ,int low,int high)
{
    int maxS = - 10000;
    result res = result();
    for(int i = 0;i < a.size();i ++){
        int sum = a[i],j,max2 = - 10000;
        result res2 = result();//**这里要注意
        for(j = i + 1;j < a.size();j ++){
            //if(sum > sum + a[j]) break;
            sum += a[j];
            if(sum > max2){
                max2 = sum;
                res2 = result(i,j,sum);
            }
        }
        if(max2 >= maxS) {
            res = res2;maxS = max2;
        }
    }
    return res;
}

方法三:巧妙求解

result resolve3(vector<int>&a,int low,int high)
{
    int sum = 0,l = 0,h = 0,maxS = - 10000;
    for(int i = 0;i < a.size();i ++){
        sum += a[i];
        if(sum < 0){
            l = i + 1;sum = 0;
        }
        if(sum > maxS){
            maxS = sum;
            h = i;
        }
    }
    return result(l,h,maxS);
}

完整代码

//最大连续子序列问题

#include <iostream>
#include <vector>

using namespace std;

class result{
public:
    result(){
        low = high = sum = 0;
    }
    result(int a,int b,int c):low(a),high(b),sum(c){};
    bool operator>=(const result &b){
        if(sum >= b.sum) return true;
        return false;
    }
    int low,high,sum;
};

template<typename T>
T Max(T a,T b,T c){
    if(a >= b && a >= c) return a;
    if(b >= a && b >= c) return b;
    return c;
}

result find_cross_max(vector<int>&a,int low,int high){
    int mid = (high + low)/2;
    int sumR = -1000,sumL = -1000;//-INF,这里假设是1000
    int R = 0,L = 0;
    int sum = 0;
    for(int i = mid;i >= low;i --){
        sum += a[i];
        if(sum > sumL){
            sumL = sum;L = i;
        }
    }
    sum = 0;
    for(int i = mid + 1;i <= high;i ++){
        sum += a[i];
        if(sum > sumR){
            sumR = sum;R = i;
        }
    }
    return result(L,R,sumR+sumL);
}

result resolve1(vector<int>&a ,int low,int high)
{
    if(low == high) return result(low,high,a[low]);
    //分治
    int mid = (high + low)/2;
    result r1 = resolve1(a,low,mid);
    result r2 = resolve1(a,mid+1,high);
    //跨越两者的数据
    result M = find_cross_max(a,low,high);
    return Max(r1,r2,M);
}

result resolve2(vector<int>&a ,int low,int high)
{
    int maxS = - 10000;
    result res = result();
    for(int i = 0;i < a.size();i ++){
        int sum = a[i],j,max2 = - 10000;
        result res2 = result();//**这里要注意
        for(j = i + 1;j < a.size();j ++){
            //if(sum > sum + a[j]) break;
            sum += a[j];
            if(sum > max2){
                max2 = sum;
                res2 = result(i,j,sum);
            }
        }
        if(max2 >= maxS) {
            res = res2;maxS = max2;
        }
    }
    return res;
}

result resolve3(vector<int>&a,int low,int high)
{
    int sum = 0,l = 0,h = 0,maxS = - 10000;
    for(int i = 0;i < a.size();i ++){
        sum += a[i];
        if(sum < 0){
            l = i + 1;sum = 0;
        }
        if(sum > maxS){
            maxS = sum;
            h = i;
        }
    }
    return result(l,h,maxS);
}

int main()
{
    vector<int> a{13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};
    result r  = resolve1(a,0,a.size() - 1);
    //    r = resolve2(a,0,a.size() - 1);
//    r = resolve3(a,0,a.size() - 1);
    cout << r.low << " " << r.high << " " << r.sum << endl;
    return 0;
}


总结与心得

经典的问题总是值得推敲的,本题源自《算法导论》第三版 Page 67
个人Github入口

猜你喜欢

转载自blog.csdn.net/lishang6257/article/details/83001394