最大子列和问题

问题描述

image.png

问题分析

求一个最大子列和,其子列的开头和结尾必然不是负数,怎么能够最快的求出最大子列和呢?解决思路如下

解决思路

1th

最简单最暴力的方法便是求出每一个子列,并且算出每个之列的和

Code

//ElementType可以是任何符合比较要求的数据类型,不一定是整数,可以是浮点数
temp = 0
sum = 0;
ElementType number[ size ];
for(int i  = 0; i < size; i++){
    for(int j = i; j < size; j++){
        for(int k = i; k <= j; k++)
            temp += number[k];
        if( temp > sum )
            sum = temp;
        temp = 0;
        }
}

这个算法简单,暴力,但是就是花费时间太慢了。时间复杂度达到了O(n3),这是一个难以忍受的结果,如果 n = 106 Emmmmm........

2th

也许你会发现第三个for是多余的,每次计算temp的时候都需要重复计算,所以我们可以对此优化一下

Code

sum = 0;
ElemenType number[size];
for(int i = 0; i < size; i++){
    for(int j = i; j < size; j++){
        temp += number[j];
        if( temp > sum )
           sum = temp;
        }
    temp = 0;
}

去掉了第三个循环时间复杂度变成了O(n2),比起原来的算法快了n倍。但是时间复杂度为O(n2)的算法仍然没有办法应付很大的数据,不用着急,我们还有一个更好的版本,时间复杂度可以达到O(n)级别

3th

给定序列{ -2, 11, -4, 13, -5, -2 },其连续子列{ 11, -4, 13 }有最大的和20

思路如下:
我们知道一个最大子列和,其子列的首和尾必然不能是一个负数,所以当我们遍历一个数组的时候遇到正数便可以开始我们的子列了,开始子列之后遇到正数自然好办,一直扩充即可。但是遇到负数怎么办?我们知道最大子列里面是可以包含负数的!但是加入负数也会可能破坏最大子列。我们应该怎么做?所以在这里引入一个gradient,当我们的子列遇到负数时gradient开始发挥作用

经过观察我们发现,负数能不能引入子列。需要看后面有没有正数,并且正数与之前的负数相加可不可以大于或等于零。如果大于或等于零我们便可以将gradient的这些数纳入到到子列。因此gradient用于记录遇到负数之后的数字的和,一旦 gradient >= 0 我们便把gradient的数列加入我们的最大子列,更新一下我们当前子列和并清零gradient

但是只有gradient是不行的,必须要给gradient提供一个上限,如果gradient的绝对值大于当前子列。该子列便不可能再增长了。换句话说,什么时候子列没有增长的可能了就是没有数或者gradient与当前子列和相加小于零

gradient与子列和相加小于零时,从哪里开始继续寻找最大子列?从遍历时让子列爆掉的数继续遍历下去直至遇到正数便可,可能有人会问为什么会是在这里,而不是之前的数?

让我们把开始子列的数到爆掉的数分为两块,一块是已经确定的子列,一块是gradient(注意前面所说,当gradient >= 0时,子列便会被扩大,同时gradient清零 因此爆掉时,gradient是负数并且绝对值大于子列和)

如果从子列开始重新找最大子列,可是当遇到之前的gradient仍旧会爆掉,因此从子列寻找舍弃,那么gradient呢。gradient虽然可以有正数,但是有了这个正数,仍旧让子列爆掉,所以该正数之后的负数的绝对值显然会比这个正数大

因此我们只需一直往下遍历直至遇到正数开始新的子列即可,这也是为什么这个算法为什么会达到O(n)的原因!我们只需要遍历一遍便可以找到最大子列和

Example:
给定序列{ -2, 11, -4, -1, 13, -5, -2 }(与上的数列不相同)最大子列和为19
step 1>>> -2<0 不开始子列
step 2>>> 11>0 开始子列 子列和为11
step 3>>> -4<0 遇到负数,gradient开始工作,记录 -4 但是现在子列还是有增长的可能!子列和为11
step 4>>> -1<0 遇到负数,记录-1,gradient变成 -5 ,子列仍有增长的可能 子列和为11
step 5>>> 13>0 遇到正数,gradient与之相加大于0,更新gradient为8,更新子列和,子列和为19 ,gradient清零。Tips:gradient只有大于或等于零才会清零,更新子列和
step 6>>> -5<0 gradient = -5,子列和为19
step 7>>> -2<0 gradient = -7,子列和为19
step 8>>> 没有数字,因此最大子列和为19

Code

#include<stdio.h>
#include<math.h>
int main(void) {
    int mark;
    int length;
    int Max = 0;
    int gradient = 0;
    int number;
    int temp = 0;
    scanf("%d",&length);

    for (int i = 0; i < length; i++) {
        scanf("%d",&number);
        if (number >= 0)
            temp += number;
        else {
            for ( ; i < length; i++) {
                gradient += number;
                if (gradient >= 0) {
                    temp += gradient;
                    gradient = 0;
                }
                else if ( -gradient > temp) {
                    if (Max < temp)
                        Max = temp;
                    gradient = temp = 0;
                    break;
                }
                scanf("%d",&number);
            }
            if (temp > Max)
                Max = temp;
        }
    }
    printf("%d\n", Max);
    return 0;
}

上述代码是实时输入数字,不是从数组获取。但是思路是一样的

解决这个问题的思想可以简述为,但遇到与目标相反的向量时,判断是否大于目标向量。如果大于,便知为当前最大向量。如果小于,便还有可能会继续增长向量

向量是抽象化的说法,因为一时找不到更好的说法 在最大子列和问题中,不断扩大子列和便是目标向量,遇到负数便是遇到与目标相反的向量

有了这个思想,最大子列乘积相信你也能解决

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342