分治算法——最大子数组

  表示很久没有接触算法了,好多东西真心要一点点拾掇起来,为了找份好工作,我也是蛮拼的了。

  好吧,下来说说分治算法,因为在leetcode上刚好碰到这么个问题,想到要用分治做,但是一时又不清楚具体步骤。于是抱起《算法导论》啃起来。刚好上面的例子也是这个算法,就研读了一下。

  假定,我们要寻找子数组A[low...high]的最大字数组,使用分治算法,其结果必定是以下三种情况中的一个:

  1.完全位于子数组A[low...mid]中,因此low <= i <= j <= mid

  2.完全位于子数组A[mid+1...high]中,因此mid < i <= j <= high

  3.在mid位置的两边,包含mid位置。因此low <= i <= mid < j <= high

  对于1和2,我们可以递归地求解,将他们子问题的结果逐层往上返回,就获得mid左右两边的最大字数组(但不包括情况3)。现在我们要做的,就是针对情况3,进行处理。

  函数代码如下:

def cross_mid_maxsub(self,A,low,mid,high):
    left_s = float(‘-inf‘)   #当前最大值,默认负无穷
    sum = 0   #我们得到的子串的和
    for i in range(mid,low-1,-1):  #因为一定要有mid,故从mid开始
        sum += A[i]
        if sum > left_s:
            left_s = sum
            max_left = i  #记录最大子串左侧起始位置

    right_s = float(‘-inf‘)
    sum = 0
    for i in range(mid+1,high+1):
        sum += A[i]
        if sum > right_s :
            right_s = sum
            max_right = i  #记录最大子串左侧起始位置
    return (max_left , max_right , left_s + right_s)

  好了,现在3种情况都已经搞定了。下面就可以直接递归求解了。

def max_sub(self,A, low, high):
    if high == low:   #防止只有1个元素的情况
        return (low, high, A[low])
    else:
        mid = (low+high)/2
        left_low, left_high, left_s = max_sub(self, A, low, mid)   #递归求情况1
        right_low, right_high, right_s = max_sub(self, A, mid+1, high)  #递归求情况2
        cross_low, cross_high, cross_sum = cross_mid_maxsub(self, A, low, mid, high)  #递归求情况3
        if left_s >= right_s and left_s >= cross_sum:
            return left_low, left_high, left_s
        elif right_s >= left_s and right_s >= cross_sum:
            return right_low, right_high, right_s
        else:
            return cross_low, cross_high, cross_sum

  上面的步骤是,先递归地找出情况1的最大值,然后找出情况2的最大值,然后找出包含mid的,也就是情况3的最大值。然后比较一下,返回其中的最大值,再回溯到上一层继续求。基本的思路是这样的了。其实这还是个比较简单的算法嘛~

时间: 2024-08-29 05:39:12

分治算法——最大子数组的相关文章

【算法设计-分治】最大子数组问题

1.问题描述 算法导论上38页,最大子数组给出一组数组来,然后求出使得从i到j的数组值的和最大的边界i与j.如果不用分治的方法的话,需要通过暴力方法来寻找n(n-1)/2种. 方法: 2代码: #include<iostream> using namespace std; typedef struct maximum { int left; int right; int sum; }Maximum; Maximum* FIND_MAX_CROOSING_SUBARRAY(int *A,int

分治策略 &nbsp; 最大子数组问题

递归式 递归式与分治方法是紧密相关的,因为使用递归式可以很自然地刻画分治算法的运行时间.一个递归式就是一个等式或不等式,它通过更小的输入上的函数值来描述一个函数.例如,在2.3.2节,我们用递归式描述了MERGE-SORT过程的最坏情况运行时间T(n): Θ(1)        若n=1 T(n) =                         (4.1) 2T(n/2)+Θ(n)    若n>1 求解可得T(n)=Θ(nlgn) 递归式可以有很多形式.例如,一个递归算法可能将问题划分为规模

第四章 分治策略——最大子数组问题

最大子数组问题 方法一:暴力求解方法 我们可以很容易地设计出一个暴力方法来求解本问题:简单地尝试没对可能的子数组,共有O(n2)种 #include<iostream> using namespace std; #define INT_MIN 0x80000000 int main() { int arr[10]={9,8,-3,-5,7,-39,79,-37,8,9}; int i,j; int sum=0,maxsum=INT_MIN; int imax; for(i=0;i<10;

2.分治算法研究-搜索数组中的最大连续子集和 2014-3-11 11:37 阅读(16)

//分治算法研究var cc=consolefunction find_max_crossing_subarray(A,low,mid,high){    var max_left=mid,max_right=mid    var left_sum=0    var sum=0    for(var i=mid;i>=low;i--){        sum=sum+A[i]        if(sum>left_sum){            left_sum=sum           

算法导论3:最大子数组问题 2016.1.3

顶着期末复习的压力,还是在今天过完之前看完了一个算法——最大子数组问题. <算法导论>中引入这个问题是通过股票的购买与出售,经过问题转换(转换的过程比较简单,但是不好想),将前一天的当天的股票差价重新表示出来,即转为了一个最大子数组的问题 ,具体内容是:   13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7   找到这连续的16个数里面的连续和最大的子数组;   书中差不多是这个意思:假定我们要寻找子数组A[lo

第四章 分治策略 4.1 最大子数组问题 (暴力求解算法)

/** * 最大子数组的暴力求解算法,复杂度为o(n2) * @param n * @return */ static MaxSubarray findMaxSubarraySlower(int[] n) { long tempSum = 0; int left = 0; int right = 0; long sum = Long.MIN_VALUE; for (int i = 0; i < n.length; i++) { for (int j = i; j < n.length; j++

用分治和递归的思想——寻找最大子数组

寻找最大子数组的问题可描述为 输入: 一个数组,一个低位,一个高位 输出: 数组中从低位到高位中,连续和最大是多少 首先能想到的最直接的办法是暴力解决,遍历所有可能的序列组合,如果有n个元素,则需遍历的子序列有,复杂度为n2,稍有些经验的就能马上意识到,有很多重复计算在里面,比如最长的子序列计算,包含了之前所有子序列的计算.接下来我们使用分治的思想求解这个最大子序列,前一篇博文提过,分治的思想是将大问题分解为同等类型的子问题,再将子问题求解,然后合并子问题得出原问题的解,其中用到了递归的思想,因

最大子数组问题(分治策略实现)

在算法导论4.1最大子数组问题中首先提出的是暴力求解方法即计算所有子数组的组合,然后求其和,寻找最大值.这种方法运行时间为Ω(n^2).然后提出有没有更好的方法. 使用分治策略的求解方法: 寻找子数组A[low..high]的最大子数组,使用分治技术意味着要将子数组划分为两个规模尽量相等的子数组.也就是说,找到子数组的中央位置(比如mid),然后考虑求解两个子数组A[low..mid]和A[mid..high].A[low..high]的任何连续子数组A[i..j]所处的位置必然以一下三种情况之

第四章 分治策略 4.1 最大子数组问题 (减治法,别人的,拿来看看)

/** * 获得连续子数组的最大和 * * @author dfeng * */ private static long getMax(long a, long b) { return a > b ? a : b; } /** * 获得连续子数组的最大和 * * @param array * @return 最大和,此处用了Long型是为了表示当参数为null或空时,可以返回null,返回其它任何数字都可能引起歧义. */ public static Long getMax(int[] arra