最大子串和
来源:互联网 发布:淘宝的销量多久清零 编辑:程序博客网 时间:2024/05/22 07:41
又一个经典问题,对于一个包含负值的数字串array[1...n],要找到他的一个子串array[i...j](0<=i<=j<=n),使得在array的所有子串中,array[i...j]的和最大。(array[]大概有1百万个数)
#include<stdio.h>int main(){ int t,n,x,i,j,sum,max; scanf("%d",&t); for(i=1;i<=t;i++){ scanf("%d",&n); max=-101; sum=0; for(j=1;j<=n;j++){ scanf("%d",&x); sum+=x; if(sum>max) max=sum; if(sum<0) sum=0; } printf("%d\n",max); } return 0;}
总结:Kadane算法。(Kadane算法正确性的证明以及解题思路详见:最大子串和)
(1)子串和子序列之间的区别。子串是指数组中连续的若干个元素,而子序列只要求各元素的顺序与其在数组中一致,而没有连续的要求。对于一个元素数为n的数组,其含有2^n个子序列和n(n+1)/2个子串。如果使用穷举法,则至少需要O(n^2)的时间才能得到答案。卡耐基梅隆大学的Jay Kadane的给出了一个线性时间算法,我们就来看看,如何在线性时间内解决最大子串和问题。
(2)Kadane算法的执行流程,从头到尾遍历目标数组,将数组分割为满足上述条件的子串,同时得到各子串的最大前缀和,然后比较各子串的最大前缀和,得到最终答案。我们以array={−2, 1, −3, 4, −1, 2, 1, −5, 4}为例,来简单说明一下算法步骤。通过遍历,可以将数组分割为如下3个子串(-2),(1,-3),(4,-1,2,1,-5,4),这里对于(-2)这样的情况,单独分为一组。各子串的最大前缀和为-2,1,6,所以目标串的最大子串和为6。(算法思想看不懂的话,就跟着程序走一遍,读完程序后就可以理解这个算法了)。
(3)当全部元素均为负数时,此写法依然成立,此时最大的子串和就是全部元素中的最大值。
(2014.7.7)今天在网上浏览最大子矩阵和的时候,又看到了一种最大子串和的解释,而且讲的还不错: 最大子矩阵和、最大子串和问题
1、直接穷举法。当n很大时,时间复杂度太高,不可行(需改进) (这里就不再写代码了)
2、带记忆的递推法。时间复杂度较第一种方法已经有了很大的改进,但是依然比较高(当n特别大时),时间复杂度是n*n(还需改进);还有一点就是边界初始化问题,见注释信息(b[-1]) (附上此种方法代码,依然超时)
#include<iostream>#include<cstdio>using namespace std;int a[1000005],b[1000005]; //a[]为原数组,b[j]为a[0]到a[j]的和int main(){ int t,n,i,j,sum,max; scanf("%d",&t); while(t--){ scanf("%d",&n); for(i=0;i<n;i++) scanf("%d",&a[i]); b[0]=a[0]; for(i=1;i<n;i++) b[i]=b[i-1]+a[i]; max=-101; for(i=0;i<n;i++) for(j=i;j<n;j++){ sum=b[j]-b[i-1]; //语法上没有错误,b[-1]也被访问到了,并参与了运算 if(sum>max) max=sum; } printf("%d\n",max); } return 0;}
3、DP。下面我们来分析一下最大子段和的子结构,令b[j]表示从a[0]~a[j]的最大子段和,b[j]的当前值只有两种情况:
(1) 最大子段一直连续到a[j] (2) 以a[j]为起点的子段,不知有没有读者注意到还有一种情况,那就是最大字段没有包含a[j],如果没有包含a[j]的话,那么在算b[j]之前的时候我们已经算出来了,注意我们只是算到位置为j的地方,所以最大子断在a[j]后面的情况我们可以暂时不考虑。
由此我们得出b[j]的状态转移方程为:b[j]=max{b[j-1]+a[j],a[j]} ,所求的最大子断和为max{b[j],0<=j<n} 。进一步我们可以将b[]数组用一个变量代替。
#include<iostream>#include<cstdio>using namespace std;int a[1000005];int maxSubArray(int a[],int n){ int b=0,sum=-10000000; //sum=INT_MIN ,INT_MIN包含在#include<climits>表示无穷小(相应的也有INT_MAX) for(int i=0;i<n;i++){ if(b>0) b+=a[i]; else b=a[i]; if(b>sum) sum=b; } return sum;}int main(){ int t,n,i; scanf("%d",&t); while(t--){ scanf("%d",&n); for(i=0;i<n;i++) scanf("%d",&a[i]); printf("%d\n",maxSubArray(a,n)); } return 0;}
就个人来看,感觉第三种DP跟上面的Kadane算法好像是一样的。恩,,,,,,,,, 再好好琢磨琢磨,体会体会。。。。。
- 最大子串和
- 最大和子串
- 子串最大和
- 最大子串和
- 最大子串和
- 最大和子串
- 最大子串和
- 最大子串和
- 最大子串和
- 最大子串和
- 最大子串和
- 最大子串和
- 最大子串和
- 最大子串和
- 最大子串和
- 最大子串和
- 最大子串和
- 最大连续子串和
- hdu 4770 Lights Against Dudely(回溯)
- 算法导论——lec 09 中位数和顺序统计学
- How to turn Vim into a full-fledged IDE
- 第一次写博客
- 【剑指offer】Q19:二叉树的镜像
- 最大子串和
- 创新实验室实习生每周工作总结【实习第十四周】
- hdu 2553 N皇后问题
- 周报(第十四周)
- 你的APP表现如何?
- hdu 4771 Stealing Harry Potter's Precious(bfs)
- 计算字符串中子串出现的次数
- CSS float 浮动属性详解
- .vimrc文件配置参考