最大子序列

转自 http://blog.csdn.net/luxiaoxun/article/details/7438315

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

  1. int maxSubSum1(int a[],int size )
  2. {
  3. int maxSum = 0;
  4. for ( int i = 0; i < size; i++ )
  5. for ( int j = 1; j < size; j++ )
  6. {
  7. int thisSum = 0;
  8. for ( int k = i; k <= j; k++ )
  9. thisSum += a[k];
  10. if ( thisSum > maxSum )
  11. maxSum = thisSum;
  12. }
  13. return maxSum;
  14. }

这个算法很简单,i表示子序列起始下标,j表示子序列结束下标,遍历子序列的开头和结束下标,计算子序列的和,然后判断最大子序列。很明显的看出算法复杂度是O( pow( n, 3 ) )

显然这种方法不是最优的,下面给出一个算法复杂度为O(n)的线性算法实现,算法的来源于Programming Pearls一书。在给出线性算法之前,先来看一个对穷举算法进行优化的算法,它的算法复杂度为O(n^2)。其实这个算法只是对对穷举算法稍微做了一些修改:其实子序列的和我们并不需要每次都重新计算一遍。假设Sum(i, j)是A[i] ... A[j]的和,那么Sum(i, j+1) = Sum(i, j) + A[j+1]。利用这一个递推,我们就可以得到下面这个算法:

  1. int max_sub(int a[],int size)
  2. {
  3.   int i,j,v;
  4. int max=a[0];
  5.   for(i=0;i<size;i++)
  6.   {
  7.     v=0;
  8.     for(j=i;j<size;j++)
  9.     {
  10.       v=v+a[j];         //Sum(i, j+1) = Sum(i, j) + A[j+1]
  11.       if(v>max)  max=v;
  12.     }
  13.   }
  14.   return max;
  15. }

那怎样才能达到线性复杂度呢?这里运用动态规划的思想。先看一下源代码实现:

  1. int max_sub2(int a[], int size)
  2. {
  3.   int i,max=0,temp_sum=0;
  4.   for(i=0;i<size;i++)
  5.   {
  6.       temp_sum+=a[i];
  7.       if(temp_sum>max)
  8.         max=temp_sum;
  9.       else if(temp_sum<0)
  10.         temp_sum=0;
  11.   }
  12.   return max;
  13. }

在这一遍扫描数组当中,从左到右记录当前子序列的和temp_sum,若这个和不断增加,那么最大子序列的和max也不断增加(不断更新max)。如果往前扫描中遇到负数,那么当前子序列的和将会减小。此时temp_sum 将会小于max,当然max也就不更新。如果temp_sum降到0时,说明前面已经扫描的那一段就可以抛弃了,这时将temp_sum置为0。然后,temp_sum将从后面开始将这个子段进行分析,若有比当前max大的子段,继续更新max。这样一趟扫描结果也就出来了。

全部代码:

 1 #include <stdio.h>
 2
 3 int fun1(int a[], int n_size)
 4 {
 5     int max;
 6     int temp;
 7     int i, j, k;
 8     temp = 0;
 9     max = 0;
10
11     for (i=0; i<n_size; i++)
12     {
13         for (j=i+1; j<n_size; j++)
14         {
15             temp = 0;
16             for(k=i; k<=j; k++)
17             {
18                 temp += a[k];
19                 if(temp >= max)
20                     max = temp;
21             }
22         }
23     }
24
25     return max;
26 }
27
28 int fun2(int a[], int n_size)
29 {
30     int i, j;
31     int v, max;
32     v = a[0];
33     max = a[0];
34
35     for (i=0; i<n_size; i++)
36     {
37         for (j=i+1; j<n_size; j++)
38         {
39             v += a[j];
40             if (v > max)
41                 max = v;
42         }
43         v = 0;
44     }
45     return max;
46 }
47
48 int fun3(int a[], int n_size)
49 {
50     int i;
51     int max, temp;
52     temp = 0;
53     max = 0;
54
55     for (i=0; i<n_size; i++)
56     {
57         temp += a[i];
58         if (temp > max)
59             max = temp;
60         if(temp < 0)
61             temp = 0;
62     }
63     return max;
64 }
65 int main()
66 {
67     int a[5]={6,-1,5,4,-7};
68     printf("fun1():%d\n", fun1(a, 5));
69     printf("fun2():%d\n", fun2(a, 5));
70     printf("fun3():%d\n", fun3(a, 5));
71     return 0;
72 }

运行结果:

时间: 2024-07-30 10:13:55

最大子序列的相关文章

14-高效求最长公共子序列(二维数组存不下)

/*                                   See LCS again时间限制:1000 ms  |  内存限制:65535 KB难度:3 描述 There are A, B two sequences, the number of elements in the sequence is n.m; Each element in the sequence are different and less than 100000. Calculate the length

POJ 2533 - Longest Ordered Subsequence(最长上升子序列) 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:http://poj.org/problem?id=2533 Description A numeric sequence of ai is ordered if a1 < a2 < ... < aN. Let the subsequence of the given numeric sequence (a1, a2, ..., aN) be any sequence (ai1, ai2, ..., aiK)

最大连续子序列和

对于给定的数组 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. 对于一段区间内的最大连续

最长公共子序列的代码实现

关于最长公共子序列(LCS)的相关知识,http://blog.csdn.net/liufeng_king/article/details/8500084 这篇文章讲的比较好,在此暂时不再详说. 以下是我代码实现两种方式:递归+递推: 1 #include <bits/stdc++.h> 2 using namespace std; 3 int A[100]; 4 int B[100]; 5 6 //int B[]={2,3,5,6,9,8,4}; 7 int d[100][100]={0};

hdu1231 最大连续子序列

最大连续子序列 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 22849    Accepted Submission(s): 10135 Problem Description 给定K个整数的序列{ N1, N2, ..., NK },其任意连续子序列可表示为{ Ni, Ni+1, ..., Nj },其中 1 <= i <= j

计算数组的最大子序列之和

问题描述: 计算一个给定数组的最大子序列之和 分析: 有三种方法: 1,扫描3遍,可以计算所有的子序列之和,但是复杂度为N^3. 2,扫描2遍,计算以任意元素开始的和,如果大于当前的最大值则将最大值付给它,复杂度为N^2. 3,扫描一遍,计算任意元素开始的值,如果小于零则清零,否则继续往后加. 代码实现: package c02; /**  * @project: DataStructureAndAlgorithmAnalysis  * @filename: MaxSubSum  * @vers

HDU 3998 Sequence (最长递增子序列+最大流SAP,拆点法)经典

Sequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1666    Accepted Submission(s): 614 Problem Description There is a sequence X (i.e. x[1], x[2], ..., x[n]). We define increasing subsequ

LintCode-乘积最大子序列

找出一个序列中乘积最大的连续子序列(至少包含一个数). 样例 比如, 序列 [2,3,-2,4] 中乘积最大的子序列为 [2,3] ,其乘积为6. 分析:访问到每个点的时候,以该点为子序列的末尾的乘积,要么是该点本身,要么是该点乘以以前一点为末尾的序列,注意乘积负负得正,故需要记录前面的最大最小值. 代码: class Solution { public: /** * @param nums: a vector of integers * @return: an integer */ int m

算法面试题 之 最长递增子序列 LIS

找出最长递增序列 O(NlogN)(不一定连续!) 参考 http://www.felix021.com/blog/read.php?1587%E5%8F%AF%E6%98%AF%E8%BF%9E%E6%95%B0%E7%BB%84%E9%83%BD%E6%B2%A1%E7%BB%99%E5%87%BA%E6%9D%A5 我就是理解了一下他的分析 用更通俗易懂的话来说说题目是这样 d[1..9] = 2 1 5 3 6 4 8 9 7 要求找到最长的递增子序列首先用一个数组b[] 依次的将d里面

NYOJ 36 &amp;&amp;HDU 1159 最长公共子序列(经典)

链接:click here 题意:tip:最长公共子序列也称作最长公共子串(不要求连续),英文缩写为LCS(Longest Common Subsequence).其定义是,一个序列 S ,如果分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则 S 称为已知序列的最长公共子序列. 输入 第一行给出一个整数N(0<N<100)表示待测数据组数 接下来每组数据两行,分别为待测的两组字符串.每个字符串长度不大于1000. 输出 每组测试数据输出一个整数,表示最长公共子序列长度.每组