最大子序列和问题的解_

4 篇文章 0 订阅
3 篇文章 0 订阅

问题:有数n1,n2,......,ns。求一个连续的子序列,这个序列的和最大。


这个问题有O(n^3)、O(n^2)、O(n*lgn)以及O(n)时间复杂度的解法。

下面主要说下O(n*lgn)和O(n)的解法。


1.O(n*lgn)是采用分治的思想。

前半部 后半部

4             -3              5             -2          -1            2             6             -2


    最大子序列的和可能出现在三个地方:整体出现在前半部、整体出现在后半部、横跨中间部分而占据左右两部分。

   前半部的最大子序列和为6(从A1到A3)而后半部分的最大子序列和为8(从A6到A7)。

   前半部分包含其最后一个元素的最大和是4(从A1到A4),而后半部分包含第一个元素的最大和为7(从元素A5到A7)。横跨这两部分且通过中间的和最大为4+7=11

   所以三个数的最大值为11。

    代码:

class Solution {
public:
	int maxSubSum(const vector<int>& arr) {
		int m = divide_conquer(arr, 0, arr.size() - 1);
		return m;
	}
	int divide_conquer(const vector<int>& arr, int s, int e){
		if (s == e) return arr[s];
		else{
			int m, lm, rm, lmm, rmm;
			int tmp = 0, mid = (s + e) / 2;

			lm = divide_conquer(arr, s, mid);
			lmm = arr[mid];
			for (int i = mid; i >= s; --i){
				tmp += arr[i];
				if (tmp>lmm) lmm = tmp;
			}

			rm = divide_conquer(arr, mid + 1, e);
			rmm = arr[mid+1];
			tmp = 0;
			for (int i = mid+1; i <= e; ++i){
				tmp += arr[i];
				if (tmp>rmm) rmm = tmp;
			}
			
			m = lm>rm ? lm : rm;
			if (m < (lmm + rmm)) m = lmm + rmm;
			return m;
		}
	}
};

2.O(n)的方法。

       设置一变量thisSum来记录前面所有项的累和。若thisSum小于0,则将其置为0,然后继续累加,在这过程中记录最大值。

代码:

int maxSubSum(const vector<int>& a)
{
      int maxSum = 0, thisSum = 0;
      for(int j = 0; j < a.size(); ++j)
      {
            thisSum += a[j];
            if(thisSum>maxSum) maxSum = thisSum;
            else if(thisSum<0) thisSum = 0;
       }
       return maxSum;
}
优点:

1)时间复杂度低。

2)只用对数据进行一次扫描,一旦a[i]被读入并处理了,它就不需要被记忆。因此,如果数组在磁盘上,它就可被顺序读入,在主存中不必存储数组。在任意时刻,算法都能对已经读入的数据给出子序列问题的正确答案。这种特性的算法被称为联机算法

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值