[算法导论]分治法---最大子数组

原创 2013年04月01日 13:33:16

分治策略---最大自子数组



一、分治策略的三个步骤

1、分解:将问题划分为一些子问题,子问题的形式与原问题一样,只是规模更小

2、解决:递归地求解出子问题。如果子问题的规模足够小,则停止递归,直接求解。

3、合并:将子问题的解组合成原问题的解。

二、最大子数组问题

题目描述:给定义数组A,长度为n,找出数组A中的最大子数组,例如数组A={-23,18,20,-7,12},则最大子数组为{18,20,-7,12}。

使用分治策略的求解方法:假定我们要寻找子数组A[low...high]的最大子数组,使用分治法意味着我们要将子数组划分为两个规模尽可能相等的子数组。也就是说,找到子数组的中央位置,比如mid,然后求解两个子数组A[low...mid]和A[mid + 1...high]。所以可以知道,A[low...high]的任何连续子数组A[i...j]所处的位置必然是三种情况之一:

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

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

3)跨越了中点,因此low<=i<=mid<j<=high;

    实际上,A[low...high]的一个最大子数组必然是以上三种情况中的所有子数组中和的最大者。所以,我们可以递归地求解A[low...mid]和A[mid + 1...high]的最大字数组,然后在三者中选取和最大者。

    我们可以很容易地在线型时间内求出跨越中点的最大子数组,因为它加入了限制---必须跨越中点,所以以下算法可返回跨越中点的最大子数组的和:

int Find_Max_Crossing_SubArray(int A[], int low, int mid, int high)
{
   int left_sum = -0xff;
   int sum = 0;
   for (int i = mid; i >= low; i --)
   {
      sum += A[i];
      if (sum >left_sum)
      {
         left_sum = sum;
      }
   }
   int right_sum = -0xff;
   sum = 0;
   for (int j = mid + 1; j <= high; j ++)
   {
      sum += A[j];
      if (sum > right_sum)
      {
         right_sum = sum;
      }
   }
   return left_sum + right_sum;
}

   有了一个线型时间的Find_Max_Crossing_SubArray()在手,我们就可以设计出求解最大子数组问题的分治算法代码了:

int Find_Maximum_SubArray(int A[], int low, int high)
{
   int left_sum, right_sum, cross_sum;
   if (high == low)
   {
      return A[low];
   }
   else
   {
      int mid = (low + high) / 2;
      left_sum = Find_Maximum_SubArray(A, low, mid);
      right_sum = Find_Maximum_SubArray(A, mid + 1, high);
      cross_sum = Find_Max_Crossing_SubArray(A, low, mid, high);
      if (left_sum >= right_sum && left_sum >= cross_sum)
      {
         return left_sum;
      }
      else if (right_sum >= left_sum && right_sum >= cross_sum)
      {
         return right_sum;
      }
      else
      {
         return cross_sum;
      }
   }
}

三、算法分析

     建立一个递归式来描述递归过程Find_Maximum_SubArray( )运行时间, 用T(n)表示Find_Maximum_SubArray( )求解n个元素的最大字数组的运行时间。因为前8行均为常量时间,所以T(1) = O(1). 第9和第10行给总的运行时间增加了2T(n/2)。第11行调用Find_Max_Crossing_SubArray( )花费O(n)的时间。因此对于递归情况,我们有:

T(n) = 2T(n/2) + O(n);

     所以我们可以得到Find_Maximum_SubArray( )的运行时间T(n)的递归式:

T(n) = O(1) n = 1

T(n) = 2T(n/2) + O(n) n > 1

    所以时间复杂度为O(nlg n);

四、完整代码

#include <iostream>

using namespace std;

int Find_Max_Crossing_SubArray(int A[], int low, int mid, int high)
{
   int left_sum = -0xff;
   int sum = 0;
   for (int i = mid; i >= low; i --)
   {
      sum += A[i];
      if (sum >left_sum)
      {
         left_sum = sum;
      }
   }
   int right_sum = -0xff;
   sum = 0;
   for (int j = mid + 1; j <= high; j ++)
   {
      sum += A[j];
      if (sum > right_sum)
      {
         right_sum = sum;
      }
   }
   return left_sum + right_sum;
}

int Find_Maximum_SubArray(int A[], int low, int high)
{
   int left_sum, right_sum, cross_sum;
   if (high == low)
   {
      return A[low];
   }
   else
   {
      int mid = (low + high) / 2;
      left_sum = Find_Maximum_SubArray(A, low, mid);
      right_sum = Find_Maximum_SubArray(A, mid + 1, high);
      cross_sum = Find_Max_Crossing_SubArray(A, low, mid, high);
      if (left_sum >= right_sum && left_sum >= cross_sum)
      {
         return left_sum;
      }
      else if (right_sum >= left_sum && right_sum >= cross_sum)
      {
         return right_sum;
      }
      else
      {
         return cross_sum;
      }
   }
}
int main()
{
    int A[100];
    int n;
    cout<<"Please input the number of numbers:";
    cin>>n;
    for (int i = 0; i < n; i ++)
    {
       cin>>A[i];
    }
    cout<<"最大子序列的和为:"<<Find_Maximum_SubArray(A, 0, n - 1)<<endl;
    return 0;
}


分治策略之最大子数组问题

分治策略的说明 分治策略是将一个大问题,不断分解成多个容易解决、与大问题形式相同的小问题,然后将小问题的解组合一起来得出最终大问题的解。 在分治策略中将执行如下三个步骤: 分解:将大问题分解成多个...
  • Clown_Zeon
  • Clown_Zeon
  • 2016年06月09日 19:56
  • 761

分治算法-最大子数组问题

背景不做过多介绍,现在有这么一个数组,里面都是整数型(包含负数),求最大子数组(连续几个相加最大)。例子如下: 首先我们分析问题,我们把此数组看作A[low..high],我们将要用分治法求出其最大...
  • qq_23660243
  • qq_23660243
  • 2016年03月05日 16:11
  • 1776

最大子数组的和问题--线性算法

最大子数组的和问题–线性算法 计算给定数组的最大子数组的和有很多种算法,最常见的是使用分治的策略,然而此问题用分治却增加了时间复杂度和代码复杂度。有更简单的算法,本文就将介绍一个线性时间的迭代算法。这...
  • zj0395
  • zj0395
  • 2017年07月28日 22:59
  • 425

求数组最大子序列的和

题目:给出数组{4,-3,5,-2,-1,2,6,-2},求子序列的最大和。分别用一下两种方法解决。#include // 方法1: 分治法 //时间复杂度 O(NlogN) int max3(i...
  • a253664942
  • a253664942
  • 2016年04月03日 18:55
  • 1487

算法导论——最大子数组问题

方法一: 暴力求解 #include #include #include int maxsubset(int *a,int len){ int summax=INT_MIN; ...
  • a0100034930
  • a0100034930
  • 2015年01月04日 20:28
  • 498

最大子数组问题 Maximum Subarray

Maximum Subarray: algorithm这个问题我们先看下问题的描述:问题描述Find the contiguous subarray within an array (containi...
  • liu2012huan
  • liu2012huan
  • 2016年05月02日 15:41
  • 10347

LintCode 最大子数组(3种方法)

给定一个整数数组,找到一个具有最大和的子数组,返回其最大和。 样例 给出数组[−2,2,−3,4,−1,2,1,−5,3],符合要求的子数组为[4,−1,2,1],其最大和为6 ...
  • sinat_30440627
  • sinat_30440627
  • 2017年02月08日 16:22
  • 1465

lintcode 42 最大子数组 II 解析

题目:给定一个整数数组,找出两个 不重叠 子数组使得它们的和最大。 每个子数组的数字在数组中的位置应该是连续的。 创建两个长度也为nums.size()的数组。含义为从左自右、从右自左分别遍历 !...
  • qq_23348071
  • qq_23348071
  • 2017年12月02日 22:02
  • 50

算法导论——分治法——最大子数组问题

好久没有写博客了。以后我会不定期地写一些算法的博客,分享一些算法的感想。以下的说法很多都是我自己的感想,肯定有很多不足的地方,希望大家指正。 今天把算法导论里面分治法这一章里面的第一个问题——最大子数...
  • songxueyu
  • songxueyu
  • 2015年07月19日 20:37
  • 822

最大子数组问题(动态规划)--【算法导论】

《算法导论》中引入这个问题是通过股票的购买与出售,将前一天的当天的股票差价重新表示出来,即转为了一个最大子数组的问题,具体内容我不多说,转的内容是: 13, -3, -25, 20, -3, -16...
  • xjm199
  • xjm199
  • 2014年01月07日 10:32
  • 4562
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:[算法导论]分治法---最大子数组
举报原因:
原因补充:

(最多只允许输入30个字)