算法-最大连续子序列和

题目:给定(可能是负的)整数A1、A2、…、AN,求出并确定对应的序列的最大值。如果所有的整数都是负数,那么最大连续子数列和就是0,只是求出最大值,不需要求出具体的序列,作为这个题目的变种有很多情况下给你一个确定的数列,具体求和,大同小异,共有四种解法,按照时间复杂度来解,object-c实现,解法如下:

穷举法

这个应该是这个题目最容易想到的方式,通过循环遍历出所有的序列组合,求出最大的序列的最大值,代码如下:

-(NSInteger)maxSubsequenceSum:(NSArray *)data{

    NSInteger maxSum=0;//最大子序列的和

    for (NSInteger start=0; start<[data count]; start++) {

        for (NSInteger end=start; end<[data count]; end++) {

            NSInteger currentSum=0;//当前子序列的和
            //data[start]~data[end]子序列的和
            for (NSInteger i=start; i<=end; i++) {

                currentSum+=[[data objectAtIndex:i] integerValue];

            }
            //通过判断给最大子序列的和赋值
            if (maxSum<currentSum) {
                maxSum=currentSum;
            }
        }
    }
    return maxSum;
}

 这个算法三个循环,假设数组的长度为n,第一层循环为n,第二层循环n-start,第三层end-start,可算出时间复杂度O(n*n*n)=O(N^3),时间复杂度是跟输入长度的立方有关,如果数组过长会是一个灾难~

穷举精简版

对data[start]~data[end]子序列求和,可以由上一次求和data[start]~data[end-1]的结果加上data[end]得到,不需要重头开始计算,时间复杂度为O(N^2)

-(NSInteger)maxSubsequenceSumSecond:(NSArray *)data{
    NSInteger maxSum=0;//最大子序列的和

    for (NSInteger start=0; start<[data count]; start++) {

        NSInteger currentSum=0;//当前子序列的和

        for (NSInteger end=start; end<[data count]; end++) {
            //data[start]~data[end]子序列的和,通过end加入,不需要循环
            currentSum+=[[data objectAtIndex:end] integerValue];

            if (maxSum<currentSum) {
                maxSum=currentSum;
            }
        }
    }
    return maxSum;
}

递归版

题目中最大子序列可能在三个地方出现,左半部,右半部,跨越输入数据的中部而占据左右两部分。前两种情况递归求解,第三种情况的最大和可以通过求出前半部分最大和(包含前半部分最后一个元素)以及后半部分最大和(包含后半部分的第一个元素)相加而得到。

-(NSInteger)maxSubsequenceSumThird:(NSArray *)data  leftIndex:(NSInteger)left rightIndex:(NSInteger)right{
    if (left==right) {
        if (data[left]>0) {
            //空集也算是子序列,空集和为0,最大子序列和最小为0
            return [data[left] integerValue];
        }else{
            return 0;
        }
    }

    NSInteger center=(left+right)/2;
    NSInteger maxLeftSum=[self maxSubsequenceSumThird:data leftIndex:left rightIndex:center];
    NSInteger maxRightSum=[self maxSubsequenceSumThird:data leftIndex:center+1 rightIndex:right];

    //左半部分中包含最右边元素的子序列的最大和
    NSInteger  maxLeftBorderSum=0,leftBorderSum=0;
    for (NSInteger i=center; i>=left; i--) {
        leftBorderSum+=[data[i] integerValue];
        if (leftBorderSum>maxLeftBorderSum) {
            maxLeftBorderSum=leftBorderSum;
        }
    }
    //右半部分包含最左边的值
    NSInteger maxRightBorderSum=0,rightBorderSum=0;
    for (NSInteger i=center+1;i<right;i++) {
        rightBorderSum+=[data[i] integerValue];
        if (rightBorderSum>maxRightBorderSum) {
            maxRightBorderSum=rightBorderSum;
        }
    }
    //跨越左右部分的最大序列和
    NSInteger maxMiddleSum=maxLeftBorderSum+maxRightBorderSum;
    //左部分,右部分,跨越左右的最大序列和的最大值
    NSInteger result=maxLeftSum>maxRightSum?maxLeftSum:maxRightSum;
    return result>maxMiddleSum?result:maxMiddleSum;
}

如果left==right,那么T(1)=1,两层循环的时间的次数2/N,最后的时间复杂度T(N)=2T(N/2)+O(N),等价于2T(N/2)+N,T(N)=N*(K+1)(这个可以自己推导),T(N)=N*(k+1)=NlogN +N=O(N );

最简版

一次遍历,如果小于0,重新设置循环的位置,时间复杂度O(N):

-(NSInteger)maxSubsequenceSumFour:(NSArray *)data{
    NSInteger maxSum=0,currentSum=0;
    for (NSInteger index=0; index<[data count]; index++) {
        currentSum+=[[data objectAtIndex:index] integerValue];
        //判断当前序列的和是否为正数
        if (currentSum<0) {
            currentSum=0;
        }
        else if(maxSum<currentSum) {
            maxSum=currentSum;
        }
    }
    return maxSum;
}

还有一个极端的情况,如果都是负数,不想返回0,获取最大的负整数即可:

-(NSInteger)maxSubsequenceSumSpecial:(NSArray *)data{

    NSInteger maxSum=[[data objectAtIndex:0] integerValue],currentSum=0;

    NSInteger maxNegative=[[data objectAtIndex:0] integerValue];

    for (NSInteger index=0; index<[data count]; index++) {

        currentSum+=[[data objectAtIndex:index] integerValue];
        if (currentSum<0) {
            currentSum=0;
        }
        else if(maxSum<currentSum) {
            maxSum=currentSum;
        }
        if (maxNegative<[data[index] integerValue]) {
            maxNegative=[data[index] integerValue];
        }
    }
    return maxSum>maxNegative?maxSum:maxNegative;

}

调用如下:

    NSArray *dataSource=[[NSArray alloc]initWithObjects:@"10",@"-9",@"-3",@"8",@"-2", nil];
    MaxSubsequence  *maxSubsequence=[[MaxSubsequence alloc]init];
    NSInteger result=[maxSubsequence maxSubsequenceSum:dataSource];
    NSLog(@"最大的连续子序列的和:%ld",(long)result);

    NSInteger resultSecond=[maxSubsequence maxSubsequenceSumSecond:dataSource];
    NSLog(@"第二种最大的连续子序列的和:%ld",(long)resultSecond);

    NSInteger thirdResult=[maxSubsequence maxSubsequenceSumThird:dataSource leftIndex:0 rightIndex:dataSource.count-1];
    NSLog(@"第三种最大的连续子序列的和:%ld",(long)thirdResult);

    NSInteger fourResult=[maxSubsequence maxSubsequenceSumFour:dataSource];
    NSLog(@"第四种最大的连续子序列的和:%ld",(long)fourResult);

    NSInteger specialResult=[maxSubsequence maxSubsequenceSumSpecial:dataSource];
    NSLog(@"第四种全是负数最大的连续子序列的和:%ld",(long)specialResult);

  结果是10,数组简单定义下,重要是看过程~

时间: 2024-10-05 17:41:16

算法-最大连续子序列和的相关文章

算法:管窥算法-最大连续子序列和

1.一些逻辑比较复杂的题用离散数学来撸逻辑,逻辑就会很清楚了,就不会有错 2.经典算法问题 - 最大连续子数列和 https://www.cnblogs.com/conw/p/5896155.html 1.暴力法 复杂度O(N^3).假设数组长度为N.因为有3个嵌套的循环,每个循环最大可能次数与n的一次方成线性关系. 1 public static int B(int[] a){ 2 int n= a.length;//获取数组长度 3 int maxSum=a[0];//最大和初始化为数组第一

连续子序列最大和问题的四种经典解答

问题描述 给定(可能是负的)整数序列A1, A2,...,AN, 寻找(并标识)使Sum(Ak)(k >=i, k <= j)的值最大的序列.如果所有的整数都是负的,那么连续子序列的最大和是那个最大的负数项.最好给出给出最大和连续子序列!! 1 暴力破解法 这个问题有一个最简单直接的穷举解决法.我们看问题,既然要求里面最大的连续子序列.那么所有的连续子序列将由哪些组成呢?以数组的第一个元素为例,连续子序列必须是至少包含元素A1,也可能包含从A1到A2...以及从A1到AN.这样就有N种可能.后

算法题——最大连续子序列乘积

1 template <typename Comparable> 2 Comparable maxprod( const vector<Comparable>&v) 3 { 4 int i; 5 Comparable maxProduct = 1; 6 Comparable minProduct = 1; 7 Comparable maxCurrent = 1; 8 Comparable minCurrent = 1; 9 //Comparable t; 10 11 for

《github一天一道算法题》:分治法求数组最大连续子序列和

看书.思考.写代码! /*************************************** * [email protected] * blog: http://blog.csdn.net/hustyangju * 题目:分治法求数组最大连续子序列和 * 思路:分解成子问题+合并答案 * 时间复杂度:O(n lgn) * 空间复杂度:O(1) ***************************************/ #include <iostream> using nam

【算法小总结】最大连续子序列和最大连续子矩阵的关系与实现

求最大子矩阵和是DP中的一类题目,今天我们就来讲一下一维(序列)与二维(矩阵)最大和 一.求最大连续子序列和 只需定义sum,扫一遍,sum为负时sum=0,具体见代码 #include<cstdio> #include<algorithm> using namespace std; const int N=1000; int x,sum,n,maxn; int main() { while(scanf("%d",&n),n) { sum=0,maxn=

最大连续子序列和

对于给定的数组 numnum,一个长度为 ss 的连续子序列是指由 num_i,num_{i+1},num_{i+2}\ldots,num_{i+s-1}num?i??,num?i+1??,num?i+2??…,num?i+s−1?? 组成的序列.数组中的元素有可能为正数.负数或 00.你需要从数组中找出元素总和最大的一个连续子序列. 比如,对于数组 1,-3,2,6,-5,81,−3,2,6,−5,8,其最大连续子序列之和是 2+6-5+8=112+6−5+8=11. 对于一段区间内的最大连续

UVa 108 - Maximum Sum(最大连续子序列)

题目来源:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=3&page=show_problem&problem=44  Maximum Sum  Background A problem that is simple to solve in one dimension is often much more difficult to solve in more th

【ToReadList】六种姿势拿下连续子序列最大和问题,附伪代码(以HDU 1003 1231为例)(转载)

问题描述:       连续子序列最大和,其实就是求一个序列中连续的子序列中元素和最大的那个. 比如例如给定序列: { -2, 11, -4, 13, -5, -2 } 其最大连续子序列为{ 11, -4, 13 },最大和为20. =============================================================== 问题分析: 1.首先最朴素的方法是暴力 O(n^3) 直接两个for循环枚举子序列的首尾,然后再来个循环计算序列的和,每次更新和的最大值.

数据结构课后小作业 最大连续子序列和

题目描述:求一个序列中连续子序列和的最大值(如果全为负,则输出0) 分析思路:简单的DP题 1.分析:最开始想到的是分治,分治的复杂度是 O[n*lb(n)][姑且把lb当做以2为底的对数],由于分治的时候遇到连接处的处理问题,一不小心就想到了原来这是DP题. 2.状态转移方程: (1)sum[i]=max{sum[i-1]+base[i],base[i]}: (2)如果sum[i]<0,sum[i]=0; 3.关于状态转移方程的分析: (1)sum[i]表示前i个元素中,包含i的最大子序列和: