最大子数组问题(分治法)--【算法导论】

原创 2014年01月07日 11:44:05

这题的思想是书上的(《算法导论》),代码当然也是按照书上伪码写出的;

之前已用动态规划解决这个问题,所以问题也不用多说,简述如下:

《算法导论》中引入这个问题是通过股票的购买与出售,经过问题转换,将前一天的当天的股票差价重新表示出来,即转为了一个最大子数组的问题,具体内容我不多说,转的内容是:

13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7

找到这连续的16个数里面的连续和最大的子数组;

说一下书中的思想吧(语言组织是书中的,自认总结不会比书上好):

假定我们要寻找子数组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..high]的一个最大子数组必然是完全位于A[low..mid]中、完全位于A[mid + 1..high]中或者跨越中点的所有子数组中和最大者。

代码:

#include <iostream>

const int Infinite = -10000;
//int max_left = 0;
//int max_right = 0;

using namespace std;

int FindMaxCrossSubarray(int A[], int low, int mid, int high)  //跨越
{
    int left_sum = Infinite;
    int sum = 0;
    for (int i = mid; i >= low; i--)  //左半部的最大子数组
    {
        sum += A[i];
        if (sum >left_sum)
        {
            left_sum = sum;
            //max_left = i;
        }
    }

    int right_sum = Infinite;
    sum = 0;
    for (int i = mid + 1; i <= high; i++)  //右半部的最大子数组
    {
        sum += A[i];
        if (sum > right_sum)
        {
            right_sum = sum;
            //max_right = i;
        }
    }
    return left_sum + right_sum;
}

int FindMaxSubarray(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 = FindMaxSubarray(A, low, mid);  //前半部
        right_sum = FindMaxSubarray(A, mid + 1, high);  //后半部
        cross_sum = FindMaxCrossSubarray(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[] = {13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7};
    //int a[] = {23, -4};
    int length = sizeof(a) / sizeof(int);

    cout<<FindMaxSubarray(a, 0, length - 1)<<endl;
    //cout<<"最大子序列的下标:"<<max_left<<"->"<<max_right;
    return 0;
}


 

欢迎指点,o(∩_∩)o

最大子段和(分治与动态规划典例)

最大子段和   问题: 给定n个整数(可能为负数)组成的序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的子段和的最大值。当所给的整均为负数时...
  • ccDLlyy
  • ccDLlyy
  • 2016年08月18日 20:16
  • 2800

[算法学习笔记]分治法——最大子序列和问题

何为分治法?在上一篇文章中讲到归并排序就有提到过分治法,这里在重复一次:分治法分治法采用了递归的结构,将原问题分成几个规模较小但是类似于原问题的子问题, 通过递归的方式再来求解这些小问题,然后将子问题...
  • u014235934
  • u014235934
  • 2016年07月22日 16:52
  • 2646

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

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

算法导论第三版第四章 最大子数组和的三种解法(暴力、教材分治法、线性解法)

1.暴力求解法 该方法的思想非常简单,先找出从第1个元素开始的最大子数组,而后再从第2个元素开始找出从第2个元素开始的最大子数组,依次类推,比较得出最大的子数组。实现代码如下: /* 常规方法,时...
  • u012677715
  • u012677715
  • 2017年12月02日 11:24
  • 458

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

分治策略---最大自子数组 一、分治策略的三个步骤 1、分解:将问题划分为一些子问题,子问题的形式与原问题一样,只是规模更小 2、解决:递归地求解出子问题。如果子问题的规模足够小...
  • chuan6099
  • chuan6099
  • 2013年04月01日 13:33
  • 815

「算法导论」:分治法求最大子数组

时间复杂度:o(nlgn)
  • u014723123
  • u014723123
  • 2014年07月07日 16:54
  • 404

算法导论学习:分治策略之最大子数组问题

对于分治策略,是算法中很重要的一个环节,它能够将一个很大的问题分解为一个个的小问题,从而降低求解难度。今天,我就对《算法导论》中的最大字数组问题进行分析,并给出书中伪代码的C/C++语言表现形式,同时...
  • qq_17256847
  • qq_17256847
  • 2016年04月20日 10:50
  • 292

算法导论之分治策略:最大子数组问题

分治策略
  • WSYW126
  • WSYW126
  • 2016年03月05日 21:00
  • 552

算法导论_最大子数组问题(分治策略)

package com.wzs; import java.util.Arrays; /** * 算法导论--page41 * * @author Administrator * */...
  • adam_zs
  • adam_zs
  • 2013年02月28日 22:51
  • 1837

最大子数组问题:分治法

  • 2014年05月31日 22:33
  • 103KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:最大子数组问题(分治法)--【算法导论】
举报原因:
原因补充:

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