2020-09-06

数组最大的连续子序列和的问题

首先设数组为vector nums(n);即n长度的整型数组。
对于最大连续子序列的和的问题,有暴力法和二分法两种很普遍的方法,但是实际上还有另一种方法,可以在线性时间内得到结果。

在这个问题中,我们实际上需要确定的是连续序列的起始点和终止点。
我们不知道终止点,但我们可以考虑分别将以0,1,…,n-1为终止点的最大连续序列和算出来,那么最大的那个即为结果,如果我们定义f(i)为[0,i]区间上以nums[i]为终止点的最大连续和,f(i)可以表示为max(sum(nums[x:i]))(for x=0,1,…,i),即存在某个x,使[x,i]上和最大
按照MATLAB向量表示法,nums[x:y]表示索引对应的元素值组成的新数组,sum表示求和

按照f(i)的定义可知整个数组最大的连续子序列和是max{f(i)}(for i=0,1,…,n-1).为了获得所有f(i),势必得到f(i+1)与f(i)的关系
问题:f(i+1)跟f(i)的关系是怎样的呢?
f(i+1)是以nums[i+1]为终止点的,那么要想f(i+1)取得最大,起始点的选取x’只有两种假设:
1.假设x’<=i,f(i+1)=max(sum(nums[x’:i+1]))=nums[i+1]+max(sum(nums[x’:i]))=nums[i+1]+f(i).此时x’可知应该等于x
2.x’>i,那么x’只能等于i+1,即f(i+1)=nums[i+1],此时x’可知应该等于i+1
所以,x’到底怎么选使f(i+1)满足定义需要判断nums[i+1]与nums[i+1]+f(i)谁大谁小,即f(i)是否大于0

由此,可得递归关系

f(i+1)=f(i)>0?f(i)+nums[i+1]:nums[i+1];
x’=f(i)>0?x:i+1;

为了得到最后结果,可设一个记录max=f(0)=nums[0];每次迭代时,通过判断f(i)与max的大小关系而使max始终保持最大。另外,如果想要获取具体的区间,可以设置两个索引 left_stack=0,left=0和right=0,每次如果f(i)<0,更新left_stack=i+1,而每次需要更新max时,left=left_stack,right=i+1
C++代码如下:需要的头文件是vector、assert.h

	struct RESULT {
		int left, right;
		int max;
	};
	RESULT getMaxSubVectorSum(vector<int>const&vi)
	{
		int const Len = vi.size();
		assert(Len > 0);
		int dp = vi[0];
		int left_stack = 0;
		RESULT res{ 0, 0, vi[0] };
		for (int i = 1; i < Len; ++i) {
			//for nums[i]:
			if (dp > 0) {
				dp += vi[i];
			} else {
				dp = vi[i];
				left_stack = i;
			}
			if (dp > res.max) {
				res.max = dp;
				res.left = left_stack;
				res.right = i;
			}
		}
		return res;
	}

Thinking:通常提出f(i)的表示式的时候,我们很容易会被x如何选取带进坑中,但事实上,我们当务之急只需要直接考虑f(i)的递归表达式,因为解决了所有i上的f(i),整个问题就解决了,在这个过程中,x的选取的方法也会明晰出来

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值