最大连续子数组和算法(动态规划解释)

之前在其他博客看到了,但是算法的关键部分完全看不懂为什么要这么做,直到最近上算法课,才终于知道到底怎么来的。

问题描述:

  给出一个数组,求其最大连续子数组和

  例:数组{1,2,3,4,-5,10,-1,-1}的最大连续子数组和是子数组{1,2,3,4,-5,10}的和15

算法过程:

  这个算法能从零直接想出来的人是真的厉害,我并不可以,所以我直接描述一下这个算法是怎么算的,而不描述怎么想到的了

  首先我们把原来数组记做a,然后最关键的一步,我们需要一个等长的数组b,b[j]的含义是以下一系列和中的最大值

a[0] + a[1] + a[2] + a[3] + … + a[j]
       a[1] + a[2] + a[3] + … + a[j]
              a[2] + a[3] + … + a[j]
                     a[3] + … + a[j]
                            ……
                                a[j]

那么显然可以知道的是,b数组中的最大值,就是我们想要的a的最大连续子数组和。

接下来就是要得到数组b,初始化的话,b[0]应该为0和a[0]之中的较大者,下面探讨b[j]和b[j+1]之间的关系:

  b[j+1]只有两种取法,第一种是b[j]+a[j+1],注意b[j]本身就是最大值,所以不用再去考虑b[j]内部的情况了,第二种是a[j+1],所以

  b[j+1] = max{ b[j]+a[j+1], a[j+1] }

OK,到此这个算法其实就算完成了,下面是直接根据这个思路打的代码:

#include <stdio.h>
#include <stdlib.h>

int main() {
    int a[] = {1,2,3,4,-5,10,-1,-1};  // 原数组
    int* b = (int*)malloc(sizeof(a)); // 数组b,和原数组等长

    // 初始化
    b[0]= a[0] > 0 ? a[0] : 0;

    // 遍历构造,注意i的边界
    int length = sizeof(a) / sizeof(int); // 数组长
    for (int i = 0; i < length - 1; i++) {
        b[i+1] = b[i] + a[i+1] > a[i+1] ? b[i] + a[i+1] : a[i+1];
    }

    // 然后找出b中的最大值
    int max = b[0];
    for (int i = 1; i < length; i++)
        if (b[i] > max)
            max = b[i];

    printf("max=%i\n", max);
    return 0;
}

  然后导致我一直看不懂的地方来了,对上面这段代码进行编程上的优化,优化主要有两个地方,

  首先在上面的分析中,b[n+1]只和当前遍历到的a[n+1]和前一个b[n]直接相关,所以其实并不需要保存整个数组b,换用一个变量就可以了,其次是最大值,也是可以一遍遍历一边改的

  于是就有了目前网络上流传最多的以下这种代码:

#include <stdio.h>
#include <stdlib.h>

int main() {
    int a[] = {1,2,3,4,-5,10,-1,-1};  // 原数组
    int max = 0;
    int b = 0;

    int length = sizeof(a) / sizeof(int); // 长度
    for (int i = 0; i < length; i++) {
        b = b + a[i] > a[i] ? b + a[i] : a[i];
        max = max > b ? max : b;
    }

    printf("max=%i\n", max);
    return 0;
}

显然这个算法是o(n)时间复杂度的,讲真最近学动态规划基本o(n^3)起步。动态规划两个基本要素,首先最优子结构性质,全局最大值基于n个子问题b的最优解,而且可以看到b[j+1]是基于b[j]给出的,也就是一个问题是基于他的子问题的最优解来解决的,其次显然子问题是有交叉的,求解b[j]需要b[j-1],递归一下就需要b[j-2],由此就出现了交叉。

PS:LeetCode上题号53 最大子序和就是这个问题,但是貌似子数组长度不为0,所以初始化会有一点变化。

原文地址:https://www.cnblogs.com/guobaoxu/p/11749943.html

时间: 2024-10-18 00:26:34

最大连续子数组和算法(动态规划解释)的相关文章

最大连续子数组和算法

求最大连续子数组和问题 sample input: -1,4,-3,6,-20,4,-2,5 sample output: 7 最容易想到的就是暴力解决方法,穷举所有连续子数组的可能性,进行比较,复杂度O(n2) 代码略 复杂度为O(n)的算法: 如果arr[0]的值大于0,将max赋值为arr[0],否则赋值为0 读取下一项,累加到sum,如果sum>0,且如果sum>max,将max更新为sum的值,如果sum<0,将sum赋值为0 重复(2)直至最后一项,所得max即为所求. 代码

最大子矩阵,最大连续子数组进阶,动态规划初级,poj1050

题目描述:现给出一个N*N矩阵,要求求出拥有最大和的子矩阵的和. 例如: 这样的一个矩阵,最大子矩阵的和为15: 此题可以让人联想到求最大连续子数组,求最大子数组在上一篇文章中http://www.cnblogs.com/tz346125264/p/7560708.html. 分析:最大子矩阵可以看为求最大连续子数组拓展到二维数组上,因为矩阵的性质同样在横向竖向上需要连续,那么可以想办法将这个二维数组简化为求连续子数组. 思考: 1.要求最大子矩阵,必须保证每个矩阵都被浏览到,为了保证运行时间尽

转-求解最大连续子数组的算法

#include "stdafx.h"//暴力法求最大子数组和问题int _tmain(int argc, _TCHAR* argv[]){ int A[8] = { -6, 10, -5, -3, -7, -1, -1 }; int array_length = sizeof(A) / sizeof(A[0]);//数组大小 int sum = -10000;//记录子数组的和 int low;//记录子数组的底 int height;//记录子数组的高 for (int i = 0

[算法导论]4.1-5最大连续子数组问题

在线性时间内非递归的求数组的最大连续子数组(连续和最大的子数组). 题目给出思路为数组A[1...j+1]的最大和子数组,有两种情况:a) A[1...j]的最大和子数组; b) 某个A[i...j+1]的最大和子数组,但思考很久没有理解如何用这个思路设计线性时间算法,希望有人能给予指点. (i点是使A[1]+..+A[i]为负的一个值?) 目前的思路是,最大子数组一定位于从某个正数开始,全部求和<=0的一段数组中 从其实点i到目标点j,从第一个正数开始截取尽量长的一段数组,从第一个正数起的最大

编程算法 - 连续子数组的最大和 代码(C)

连续子数组的最大和 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 输入一个整型数组, 数组里有正数也有负数. 数组中一个或连续的多个整数组成一个子数组.求所有子数组的和的最大值. 使用一个数保存当前和, 如果当前和为小于0,  则替换新值, 否则, 递加, 使用一个数保存临时最大值. 代码: /* * main.cpp * * Created on: 2014年6月29日 * Author: wang */ #include <stdio

笔试算法题(06):最大连续子数组和 &amp; 二叉树路径和值

出题:预先输入一个整型数组,数组中有正数也有负数:数组中连续一个或者多个整数组成一个子数组,每个子数组有一个和:求所有子数组中和的最大值,要求时间复杂度O(n): 分析: 时间复杂度为线性表明只允许一遍扫描,当然如果最终的最大值为0表明所有元素都是负数,可以用线性时间O(N)查找最大的元素.具体算法策略请见代码和注释: 子数组的起始元素肯定是非负数,如果添加的元素为正数则记录最大和值并且继续添加:如果添加的元素为负数,则判断新的和是否大于0,如果小于0则以下一个元素作为起始元素重新开始,如果大于

最大连续子数组算法学习

作为零基础学习的弱智艰难的入行后,在黑暗中摸爬滚打中过了几个月,才想起应该开个博客记录下自己的学习历程和整理知识点.刚刚接触算法的我,博客就以记录我的算法学习历程为开端吧.多说无益,下面开始: 如果已知后三十天的股票涨跌停的情况,那么我该如何确定自己收益的最大值是多少呢?这里可以将股票每天的变化存进一个数组里,涨记为正,跌记为负,那么最后这个实际问题就转化为了求最大连续子数组的问题了,即我怎么切割这个数组使得这个数组里的值最大?这里简单的用了分治法去计算,首先将data分成2份,一份为左data

经典算法——连续子数组最大和问题

Find the contiguous subarray within an array (containing at least one number) which has the largest sum. For example, given the array [?2,1,?3,4,?1,2,1,?5,4], the contiguous subarray [4,?1,2,1] has the largest sum = 6. 一.问题描述:输入一个整数数组,求数组中连续的子数组使其和最大

[算法导论]练习4.1-5最大连续子数组问题

题目:在线性时间内非递归的求数组的最大连续子数组(连续和最大的子数组). 思路:设最大子数组的和为max,起点和终点位置为s.e,正在扫描的子数组的和为add,起点和终点位置为i.j.max的初始值为-∞. 1.若数组的值全为负,则返回最大值. 2.逐个扫描数组元素,更新add.i.j的值. a.若add的值为正,则和max的值比较,如果大于max的值,更新max.s.e的值为add.i.j. b.若add的值为负,则从i到j这一段的数字只能减少子数组的和,要丢弃,add值清零并重下一个元素重新