分治算法解最大子序列和问题

2019-02-10  本文已影响0人  fourkilometers
最大子序列和问题

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

这是一道经典的算法题,在LeetCode上的编号是53。
本文以这道题为例学习分治算法

分治算法

分治算法的核心是把问题分成两个大致相等的子问题,然后递归对它们求解,这是“分”的部分,在“治”这一阶段将两个子问题的解合并到一起求解。

根据算法的思想,把数组分割成两部分,左半部分和右半部分,最大子序列出现的位置可能在:

递归是这个算法里非常重要的一个环节,它把数组划分到最小单元来进行比较

1:[4,-3,5,-2,-1,2,6,-2]
2:[4,-3,5,-2] [-1,2,6,-2]
3:{[4,-3] [5,-2]} {[-1,2] [6,-2]}

把数组分成了四份,每一份只有两个元素。计算的过程是从左到右进行,比较左边元素,右边元素和两个元素之和的大小,取最大值,也就是max(4,-3,(4+(-3))),结果是4。同理,整个数组的左半部分最大值是6,最大子序列就是4,-3,5

[4,-3]=4 [5,-2]=5 
[4,-3,5,-2]=6  max(4,5,6)=6

[-1,2]=2 [6,-2]=6
[-1,2,6,-2]=8  max(2,6,8)=8

[4,-3,5,-2,-1,2,6,-2]=11

max(6,8,11)=11
算法实现

下面是用JavaScript实现的分治算法实现

/**
 * 求最大子序列和
 *
 * @param {*} array 目标数组
 * @param {*} left  左边界
 * @param {*} right 右边界
 * @returns
 */
function maxSubSum(array,left,right){
  var maxLeftSum,maxRightSum
  var maxLeftBorderSum,maxRightBorderSum
  var leftBorderSum,rightBorderSum
  var center

  if(left===right){//基准情形
    if(array[left]>0){
      return array[left]
    }
    else{
      return 0
    }
  }

  center=parseInt((left+right)/2)
  maxLeftSum=maxSubSum(array,left,center)
  maxRightSum=maxSubSum(array,center+1,right)

  maxLeftBorderSum=0
  leftBorderSum=0

  for (let i = center; i >=left; i--) {
    leftBorderSum+= array[i];
    if(leftBorderSum>maxLeftBorderSum){
      maxLeftBorderSum=leftBorderSum
    }
  }

  maxRightBorderSum=0
  rightBorderSum=0
  for (let i = center+1; i <=right; i++) {
    rightBorderSum+=array[i]
    if(rightBorderSum>maxRightBorderSum){
      maxRightBorderSum=rightBorderSum
    }
  }
  var maxSum=max3(maxLeftSum,maxRightSum,maxLeftBorderSum+maxRightBorderSum)
  return maxSum
}

function max3(a,b,c){
  var max=a>b?a:b
  max=max>c?max:c
  return max
}

maxSubSum([4,-3,5,-2,-1,2,6,-2],0,7);
算法复杂度分析

T(N)是求解大小为N的最大子序列和问题所花费的时间。

经过分析得到两个方程组
T(1)=1
T(N)=2T(N/2)+O(N)

为了简化计算,设置两个前提:

得到方程T(N)=2T(N/2)+N
两边同时除以N,得到:
\frac{T(N) }{N}=\frac{T(N/2) }{N/2}+1
这个方程对于任意2的幂都成立,所以下面的方程都是正确的

\frac{T(N/2) }{N/2}=\frac{T(N/4) }{N/4}+1\\ \frac{T(N/4) }{N/4}=\frac{T(N/8) }{N/8}+1\\ \vdots\\ \frac{T(2) }{2}=\frac{T(1) }{1}+1

一共有logN个方程,所有方程两边相加,消去相同项后得到:

\frac{T(N) }{N}=\frac{T(1) }{1}+logN

得到最终的结果:T(N)=N+NlogN=O(N log N)
以上的分析基于N是2的幂这个假设,如果不满足,方程不成立;当N不是2的幂时,需要加入一些复杂的分析,但是大O的结果不变。

上一篇 下一篇

猜你喜欢

热点阅读