最大子序列和问题从O(N^3)到线性的算法

算法复杂度,从开始学习算法分析之后就一直在讨论着这个问题,很多人都认为,计算机相关人才只是“高级蓝领”,“技术民工”,那为什么计算机的大牛们依然乐此不疲呢?我想,是因为他们发现了思考的乐趣。

有时候,稍加思考,你所做的事情就会变得格外的美妙,有时候,更简短的代码带来的却是更高的执行效率,生活,恰是需要这样的点睛之笔。

好了,前奏铺垫的有点长,下面进入正题,通过对大家所熟知的一道题的分析,最大子序列和的问题,让我们来初步感受一下编程的美丽:

题目是这样描述的,给定指定的整数序列(可能是负数)A1,A2…..An,寻找(并标识)使得Ai至Aj的连续的和值最大的子序列。

首先初步分析一下,假设输入的是1,3,-5,6,-3这五个数,那么最大的明显是1,3,-5,6所组成的子序列,包含四项,数组下标从0开始,到3为止。而对于一个全为负数的序列,最长公共子序列的和值应该是0,理由在于,由0个整数所组成的空子序列也是一个子序列。

问题分析到这里,大家应该对问题有了初步了解了,那么对于一道寻值的问题,我们一般第一反应所想到的恐怕就是“暴力求解”了,将每一个可能的子序列都找出来,然后一一比对,比如一个长度为6的序列,他的子序列的长度就有0到6这7种大情况,再把每一种情况细分(如长度为3的子序列,数组的下标索引可以是0,1,2,3),把所有的情况都列出来,这样毫无疑问是可以找到答案的,通过这样的分析,我们的O(N^3)的算法就出炉了,如下:

Java代码

/**
* O(N^3)算法
* @return 最大公共子序列的和
*/
public int maxSubsequenceSum1(int a[]){
    int maxSum=0;
    for(int i=0;i<a.length;i++){
        for(int j=i;j<a.length;j++){
            int thisSum=0;
            for(int k=i;k<=j;k++){
                thisSum+=a[k];
                if(thisSum>maxSum){
                    maxSum=thisSum;
                    seqStart=i;//最大公共子序列索引的起始坐标
                    seqEnd=j;//最大公共子序列索引的末尾坐标
                }
            }
        }
    }
    System.out.println(seqStart);
    System.out.println(seqEnd);
    return maxSum;
}

不难看出,这个算法的运行时间完全由最内层的for循环决定,而里层执行的次数正好等于满足1<=i<=k<=j<=N的有序三元组(i,j,k)的个数,大家可以自己用数学公式证明一下,这个有序三元组的个数是N(N+1)(N+2)/6。这种“暴力求解”的优点是,编码非常简单,理解起来也很容易,算法越简单就越容易正确地编程实现。不过这样的方法很明显效率偏低,三层嵌套因此导致算法的复杂度是立方级的,不过我们要注意的是,三个连续的循环表现出的是线性行为,也就是说,不是简单的N*N*N的算法。那么我们是不是可以去掉一个循环来提高程序的执行效率呢?请看以下分析:

很明显,上面的算法有很多不必要的计算,假设我们已经计算出了i,…,j-1的和,那么计算子序列i,…j的和是不是很简单呢?只需要再进行一次计算。立方算法恰恰就丢掉了这一个信息,如下的改进算法,使用的是两个而不是三个循环嵌套:

Java代码

/**
 * O(N^2)算法
 */
public int maxSubsequenceSum2(int a[]){
    int maxSum=0;
    for(int i=0;i<a.length;i++){
        int thisSum=0;
        for(int j=i;j<a.length;j++){
            thisSum+=a[j];
            if(thisSum>maxSum){
                maxSum=thisSum;
                seqStart=i;
                seqEnd=j;
            }
        }
    }
    System.out.println(seqStart);
    System.out.println(seqEnd);
    return maxSum;
}

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索算法
, 问题
, 分析
, 序列
, 下标
, 所有公共子序列
, 长公共子字符串
, 子序列
, 最大
最大子序列
最大子序列和联机算法、线性最大流算法、线性回归算法、双线性插值算法、时间序列算法,以便于您获取更多的相关知识。

时间: 2024-08-03 19:07:49

最大子序列和问题从O(N^3)到线性的算法的相关文章

最大子序列和问题

问题:  给定一整数序列A1, A2,... An (可能有负数),求A1~An的一个子序列Ai~Aj,使得Ai到Aj的和最大.  例如:整数序列-2, 11, -4, 13, -5, 2, -5, -3, 12, -9的最大子序列的和为19.对于这个问题,最简单也是最容易想到的那就是穷举所有子序列的方法.利用三重循环,依次求出所有子序列的和然后取最大的那个.当然算法复杂度会达到O(n^3). int max_sub_sum1(int a[],int size) { int maxSum = 0

深度丨110亿美金还不够,阿里使用这种AI手段创造更多广告收入(附PPT)丨CCF-GAIR 2017

7月9日,虽然已是中国计算机学会(CCF)主办,雷锋网和香港中文大学(深圳)承办的第二届CCF-GAIR全球人工智能与机器人峰会的最后一天,但仍然不影响各位童鞋到场学习的激情.机器人专场不仅满座,连走道上都挤满了小伙伴.继Facebook田渊栋结束其演讲之后,阿里妈妈精准展示广告技术总监盖坤作为第二场主题演讲嘉宾,也上台为大家分享了在过去5.6年间阿里巴巴基于互联网大数据做的机器学习模型方面的一些探索,以及一些研究成果背后的思考. 盖坤这次给大家带来的演讲主题是<互联网大数据下的模型结构挑战>

排序总结

一. 排序的基本概念 排序(Sorting)是计算机程序设计中的一种重要操作,其功能是对一个数据元素集合或序列重新排列成一个按数据元素某个项值有序的序列. 有 n 个记录的序列{R1,R2,-,Rn},其相应关键字的序列是{K1,K2,-,Kn},相应的下标序列为1,2,-,n.通过排序,要求找出当前下标序列1,2,-, n 的一种排列p1,p2, -,pn,使得相应关键字满足如下的非递减(或非递增)关系,即:Kp1≤Kp2≤-≤Kpn,这样就得到一个按关键字有序的记录序列{Rp1,Rp2,-,

经典面试题:最长公共子序列

1.问题描述: 什么是最长公共子序列呢?好比一个数列 S,如果分别是两个或多个已知数列的子序列,且是所有符合此条件序列中最长的,则S 称为已知序列的最长公共子序列.     举个例子,如:有两条随机序列,如 1 3 4 5 5 ,and 2 4 5 5 7 6,则它们的最长公共子序列便是:4 5 5.     注意最长公共子串(Longest CommonSubstring)和最长公共子序列(LongestCommon Subsequence, LCS)的区别:子串(Substring)是串的一

动态规划之最长公共子序列

给定两个序列x和y,称z是x和y的公共子序列,如果z既是x的子序列,又是y的子序列:最长的公共子序列称作最长公共子序列LCS(longest common subsequence). 解题思路 (1)LCS的最优子结构 设zk是xm和yn的一个LCS,则,如果x和y的最后一个元素相同,则z中去掉最后一个元素之后zk-1仍为xm-1和yn-1的LCS. 如果xm!=yn,若zk!=xm,则z是xm-1和y的一个LCS,若zk!=yn,则z是xm和yn-1的LCS. (2)一个递归解 设c[i][j

PHP求最大子序列和的算法实现

复制代码 代码如下: <?php //作者:遥远的期待 //QQ:15624575 //算法分析:1.必须是整数序列.2.如果整个序列不全是负数,最大子序列的第一项必须是正数,否则最大子序列后面的数加起来再加上第一项的负数,其和肯定不是最大的:3.如果整个序列都是负数,那么最大子序列的和是0: //全负数序列很简单,不举例 $arr=array(4,-3,5,-2,-1,2,6,-2); function getmaxsum($arr){ $thissum=0; $maxsum=0; $star

UVa 10405:Longest Common Subsequence,最长公共子序列模板题

[链接] http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=114&page=show_problem&problem=1346 [原题] Problem C: Longest Common Subsequence Sequence 1: Sequence 2: Given two sequences of characters, print the length of

动态规划解最长公共子序列(LCS)问题 (附可打印LCS完整代码)

一.动态规划法 经常会遇到复杂问题不能简单地分解成几个子问题,而会分解出一系列的子问题.简单地采用把大问题分解成子问题,并综合子问题的解导出大问题的解的方法,问题求解耗时会按问题规模呈幂级数增加. 为了节约重复求相同子问题的时间,引入一个数组,不管它们是否对最终解有用,把所有子问题的解存于该数组中,这就是动态规划法所采用的基本方法. 二.问题:求两字符序列的最长公共字符子序列(LCS) 问题描述:字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的

最长递增子序列(LIS)的O(N^2)与O(NlogN)算法分析

题目: 求一个一维数组arr[n]中的最长递增子序列的长度,如在序列1,5,8,3,6,7中,最长递增子序列长度为4 (即1,3,6,7). 由于LIS用O(NlogN)也能打印,O(N^2)的DP方法见最后. 从LIS的性质出发,要想得到一个更长的上升序列,该序列前面的数必须尽量的小. 对于原序列1,5,8,3,6,7来说,当子序列为1,5,8时,遇到3时,序列已经不能继续变长了.但是,我们可以通过替换,使"整个序列"看上去更小,从而有更大的机会去变长.这样,当替换5-3和替换8-6