【算法导论】最大子数组

1.描述:找出数组A的和最大的非空连续子数组,我们称这样的连续子数组为最大子数组。

  

2. 用分治策略来求解。

  a. 假设我们要求A的子数组A[low, high]的最大子数组。根据分治策略,我们先将A[low,high] 平分

  b. 那么 A[low,highj]的子数组A[i,j]只有三种可能

    a)完全位于A[low, mid]; 此时 low <= i <= j <= mid

    b)  完全位于A[nid+1, high]中,此时 mid + 1 <= i <= j <= high

    c)  跨越了中点mid, 此时 low <= i  <= mid < j < high

3.  伪代码

FIND-MAXIMUM-SUBARRAY(A, low, high)
    if high == low
        return (low, high. A[low])   //只有一个元素
    else
        mid = (low + high)/2     //向下取整
        (left-low, left-high, left-sum) = FIND-MAXIMUM-SUBARRAY(A, low, mid)
        (right-low, right-high, right-sum) = FIND-MAXIMUM-SUBARRAY(A, mid + 1, high)
        (cross-low, cross-high, cross-sum) = FIND-MAX-CROSSING-SUBARRAY(A, low, mid, high)
        if left-sum >= right-sum and left-sum >= cross-sum
            return (left-low, left-high, left-sum)
        else if right-sum >= left-sum and right-sum >= cross-sum
             return (right-low, right-high, right-sum)
        return (cross-low, cross-high, cross-sum)

FIND-MAX-CROSSING-SUBARRAY(A, low, mid, high)
    left-sum = -∞
    sum = 0
    for i = mid downto low
        sum = sum + A[i]
        if sum > left-sum
            left-sum = sum
            max-left = i
    right-sum = -∞
    sum =0;
    for j = mid + 1 to high
        sum = sum + A[j]
        if sum > right-sum
            right-sum = sum
            max-right = j
    return (max-left, max-right, left-sum + right-sum)

4. 分析

  我之前说过,所有的比较最后都是两个数比较。把最大子数组通过分治策略最后都是一个元素,这时候就是直接返回这个数,交给上一层。

  这时候数组有两个数,子数组就到了2所说的比较三种情况,再一层层向上递交结果

5. 代码实现

java

public class MaxArray {

    private static class Result {
        int low;
        int high;
        int sum;

        public Result(int low, int high, int sum) {
            this.low = low;
            this.high = high;
            this.sum = sum;
        }
    }

    static Result findMaximumSubarray(int[] A, int low, int high) {
        if (low == high) {
            return new Result(low, high, A[low]);
        } else {
            int mid = (low + high)/2;
            Result leftResult = findMaximumSubarray(A, low, mid);
            Result rightResult = findMaximumSubarray(A, mid+1, high);
            Result crossResult = findMaxCrossingSubarray(A, low, mid, high);
            if (leftResult.sum >= rightResult.sum && leftResult.sum >= crossResult.sum)
                return leftResult;
            else if (rightResult.sum >= leftResult.sum && rightResult.sum >= crossResult.sum)
                return rightResult;
            else return crossResult;
        }

    }

    static Result findMaxCrossingSubarray(int[] A, int low, int mid, int high) {

        //向左试探
        int leftSum = Integer.MIN_VALUE;   //哨兵
        int maxLeft = mid;
        int sum = 0;
        for (int i = mid; i >= low; i--) {
            sum += A[i];
            if (sum > leftSum) {
                leftSum = sum;
                maxLeft = i;
            }
        }
        //向右试探
        int rightSum = Integer.MIN_VALUE;
        int maxRight = mid + 1;
        sum = 0;
        for (int j = mid + 1; j <= high; j++) {
            sum += A[j];
            if (sum > rightSum) {
                rightSum = sum;
                maxRight = j;
            }
        }
        //将两边的结果合起来
        return new Result(maxLeft, maxRight, leftSum + rightSum);
    }

    public static void main(String[] args) {
        int[] A = {-1, 5, 6, 9, 10, -9, -8, 100, -200};
        Result result = findMaximumSubarray(A, 0,  A.length-1);
        System.out.println(result.low + "," + result.high + " " + result.sum);
    }
}

python

def find_maximum_subarray(nums, low, high):
    if low == high:
        return {"low": low, "high": high, "sum": nums[low]}
    else:
        mid = int((low + high) / 2)
        left_result = find_maximum_subarray(nums, low, mid)
        right_result = find_maximum_subarray(nums, mid + 1, high)
        cross_result = find_max_crossing_subarray(nums, low, mid, high)
        if left_result["sum"] >= right_result["sum"] and left_result["sum"] >= cross_result["sum"]:
            return left_result
        else:
            if right_result["sum"] >= left_result["sum"] and right_result["sum"] >= cross_result["sum"]:
                return right_result
            else:
                return cross_result

def find_max_crossing_subarray(nums, low, mid, high):
    left_sum = -float(‘inf‘)
    total = 0
    max_left = mid
    for i in range(mid, low-1, -1):
        total += nums[i]
        if total > left_sum:
            left_sum = total
            max_left = i

    rigth_sum = -float(‘inf‘)
    total = 0
    max_right = mid + 1
    for j in range(mid+1, high+1):
        total += nums[j]
        if total > rigth_sum:
            rigth_sum = total
            max_right = j

    return {"low": max_left, "high": max_right, "sum": left_sum + rigth_sum}

if __name__ == "__main__":
    numss = [-1, 5, 6, 9, 10, -9, -8, 100, -200]
    result = find_maximum_subarray(numss, 0, len(numss)-1)
    print(result)

再分享个python用切片的方法

def find_maximum_subarray_slice(nums):
    max_sum = -float(‘inf‘)
    result = {}
    for i in range(len(nums)+1):
        for j in range(i, len(nums)+1):
            total = sum(nums[i:j])
            if total > max_sum:
                max_sum = total
                result["low"] = i
                result["high"] = j-1
    result["sum"] = max_sum
    return result

C语言

结构体没有学好,晚点贴。。

原文地址:https://www.cnblogs.com/yeyeck/p/9574778.html

时间: 2024-08-01 12:47:08

【算法导论】最大子数组的相关文章

(算法)最大子数组和以及最大子矩阵和

题目: 1.给定一数组,求该数组的最大子数组和: 2.给定一矩阵,求该矩阵的最大子矩阵和: 思路: 1.求数组的最大子数组和很简单,可以通过动态规划来实现,假设数组为arr: 假设dp[i]表示从0到i的数组的最大子数组和,那么递推关系式表示为: dp[0]=arr[0]; dp[i]=dp[i-1]>0?dp[i-1]+arr[i]:arr[i] 2.求矩阵的最大子矩阵和看似很难,其实也可以转化为最大子数组和的问题.假设矩阵为matrix 首先,我们求出矩阵每个位置按行叠加的结果,设叠加结果矩

算法:最大子数组own

转载标明出处:http://i.cnblogs.com/EditPosts.aspx?postid=4726782&update=1 暴力法: 1 // maxValue.cpp : 定义控制台应用程序的入口点. 2 // 3 4 #include "stdafx.h" 5 #include <iostream> 6 7 using namespace std; 8 9 int findMax(int *a,int low,int high,int &sub

使用分治算法求解最大子数组问题

def MaxCrossSubarray(num,mid,low,high): leftsum=0 leftmax=-1000000 rightsum=0 rightmax=-1000000 for i in range(mid,low-1,-1): leftsum=leftsum+num[i] if leftsum>leftmax: leftmax=leftsum leftlow=i for j in range(mid+1,high+1): rightsum=rightsum+num[j]

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

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

算法导论笔记2 - T(n) = O(n) 的最大子数组问题解法

import random __author__ = 'Administrator' LENGTH = 500 base = [] for i in range(0, LENGTH * 2): base.append(random.randint(-1 * LENGTH, LENGTH)) print(base) bsa_i = 0 bsa_j = 1 bsa = base[0] bord = base[0] bord_i = 0 for i in range(1, len(base)): if

算法导论4.1寻找最大子数组

寻找最大子数组 // find_max_sub_array.h #include <stdint.h> int Find_MAX_CROSSING_SUBARRAY(int* A, int low, int mid, int high, int& max_left, int& max_right, int& max_value) { int left_sum = 0xFFFFFFFF; // 不可能的最小值 int sum = 0; for(int i = mid; i

【算法导论】最大子数组问题

寻找数组A的和最大的非空连续子数组.例如:int A[] = {1, -2, 3, 10, -4, 7, 2, -5}的最大子数组为3, 10, -4, 7, 2,其最大和为18. 方法1:枚举所有子数组并求出他们的和. 长度为n的数组有O(n2)个子数组(即:n + n-1 + ... + 1=n(n+1)/2):而且求一个长度为n的数组的和的时间复杂度为O(n).因此这种思路的时间复杂度是O(n3). 1 #include <iostream> 2 #include <vector&

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

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

第四章 分治策略 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++