《算法导论》学习笔记——寻找最大子数组

寻找最大子数组

1.问题描述

  给定一个数组A,找到数组A的一个子数组使得该子数组内所有元素的和最大。当然,如果A中的元素恒为正或恒为负,那么A的最大子数组即为A自身或A中最大的负数,这是很简单的情况。但如果A中的元素有正有负,问题就比较复杂。如下面的数组A,其最大子数组应该为{18,20,-7,12}。

191340035636832.png

  如果采用暴力求解法,那么需要我们至少需要检查n(n-1)/2,即组合数Cn2,所以暴力求解法的算法复杂度为O(n2)(n2:n*n,即n的平方)。所以我们采用一种较好的方法来求解最大子数组——分治法。

2.使用分治策略求解最大子数组

  假设我们要寻找数组A[low...high]的最大子数组,分治法的策略即为我们要将数组尽量等分为两个规模一样的数组,因此。可以找到数组的中间位置mid,然后求解两个子数组A[low...mid]和A[mid+1...high]。如下图所示,A[low...high]的任何连续子数组A[i...j]必然属于下列情况:
  - 完全位于子数组A[low...mid]中,因此low <= i <= j <= mid;
  - 完全位于子数组A[mid+1...high]中,因此mid < i <= j <= high;
  - 跨域了中点mid,因此low <= i <= mid < j <= high.

191340310165553.png

  因此,A[low...high]的最大子数组必然属于上述三种情况之一,对于前两种情况,我们只需采用分治策略递归地求解最大子数组即可;我们要思考的只是对于跨域中点的子数组的求解以及在这三种情况中选取最大的子数组。这也是容易求得的,根据上面的分析,任何跨越了中点的子数组都是由两个子数组A[low...mid]和A[mid+1...high]组成,且满足条件low <= i <= mid < j <= high。因此,我们只需要找出形如A[low...mid]和A[mid+1...high]的最大子数组,然后将其合并即可。

  最后对算法复杂度进行评价:采用分治策略求解最大子数组的算法复杂度为O(nlogn)

3.代码实现(C,Java,Python)

C

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

typedef struct {
    int left;
    int right;
    int sum;
}Subarray;

Subarray subarray;

Subarray findMaxCrossSubarray(int* array, int low, int mid, int high) {
    int i, left_sum , right_sum;
    left_sum = right_sum = INT_MIN;
    Subarray subarray_cross;
    subarray_cross.sum = 0;
    for(i = mid; i >= low; i--) {
        subarray_cross.sum += array[i];
        if(subarray_cross.sum > left_sum) {
            left_sum = subarray_cross.sum;
            subarray_cross.left = i;
        }
    }
    subarray_cross.sum = 0;
    for(i = mid + 1; i <= high; i++) {
        subarray_cross.sum += array[i];
        if(subarray_cross.sum > right_sum) {
            right_sum = subarray_cross.sum;
            subarray_cross.right = i;
        }
    }
    subarray_cross.sum = left_sum + right_sum;
    return subarray_cross;
}

Subarray findMaxSubarray(int* array, int low, int high) {
    int mid;
    Subarray subarray_left;
    Subarray subarray_right;
    Subarray subarray_cross;
    if(low == high) {
        subarray.left = low;
        subarray.right = high;
        subarray.sum = array[low];
        return subarray;
    }
    else {
        mid = (low + high) / 2;
        subarray_left = findMaxSubarray(array, low, mid);
        subarray_right = findMaxSubarray(array, mid + 1, high);
        subarray_cross = findMaxCrossSubarray(array, low, mid, high);
        if(subarray_left.sum > subarray_right.sum && subarray_left.sum > subarray_cross.sum)
            return subarray_left;
        else if(subarray_right.sum > subarray_left.sum && subarray_right.sum > subarray_cross.sum)
            return subarray_right;
        else
            return subarray_cross;
    }
}

int main() {
    int *array, len, i;
    printf("Enter the length of the array: ");
    scanf("%d", &len);
    array = (int* )malloc(len * sizeof(int));
    for(i = 0; i < len; i++)
        scanf("%d", &array[i]);
    subarray = findMaxSubarray(array, 0, len - 1);
    printf("The index of the maximum subarray form %d to %d, and the sum is %d.\n", \
                             subarray.left + 1, subarray.right + 1, subarray.sum);
    printf("The maximum subarry is consist of: ");
    for(i = subarray.left; i <= subarray.right; i++)
        printf("%d ", array[i]);
    return 0;
}

Java

import java.util.*;

public class FindMaxSubarray {
    public static void main(String[] args){
        Scanner in = new Scanner(System.in);
        ArrayList<Integer> array = new ArrayList<Integer>();
        HashMap<String, Integer> subarray = new HashMap<String, Integer>();
        System.out.print("Enter the length of array: ");
        int length = in.nextInt();
        System.out.print("Enter the elements of array: ");
        for(int i = 0; i < length; i++)
            array.add(in.nextInt());
        in.close();
        Find find = new Find(array);
        subarray = find.findSubArray(find.getLow(), find.getHigh());
        System.out.print("The value of the maximum subarray is " + subarray.get("sum") + 
                " , from the index " + (subarray.get("low") + 1) + " to the index " + 
                (subarray.get("high") + 1) + ".");
        System.out.print("The elements of the maximum subarray are: ");
        for(int i = subarray.get("low"); i <= subarray.get("high"); i++)
            System.out.print(array.get(i) + " ");
        System.out.print(".");
    }
}

class Find{
    public Find(ArrayList<Integer> array) {
        this.array = array;
    }

    public HashMap<String, Integer> findSubArray(int low, int high){
        if (low == high){
            subarray.put("low", low);
            subarray.put("high", high);
            subarray.put("sum", array.get(low));
            return subarray;
        }
        else {
            int mid = (low + high) / 2;
            subarrayLeft = findSubArray(low, mid);
            subarrayRight = findSubArray(mid + 1, high);
            subarrayCross = findMaxCrossSubarray(low, mid, high);
            if (subarrayLeft.get("sum") >= subarrayRight.get("sum") &&
                    subarrayLeft.get("sum") >= subarrayCross.get("sum")){
                return subarrayLeft;
            }
            else if (subarrayRight.get("sum") >= subarrayLeft.get("sum") && 
                    subarrayRight.get("sum") >= subarrayCross.get("sum")){
                return subarrayRight;
            }
            else {
                return subarrayCross;
            }
        }
    }
    
    public HashMap<String, Integer> findMaxCrossSubarray(int low, int mid, int high){
        int sum = 0;
        int leftSum = Integer.MIN_VALUE;
        int maxLeft = 0;
        for (int i = mid; i >= low; i--){
            sum += array.get(i);
            if (sum > leftSum){
                leftSum = sum;
                maxLeft = i;
            }
        }
        int rightSum = Integer.MIN_VALUE;
        int maxRight = 0;
        sum = 0;
        for (int i = mid + 1; i <= high; i++){
            sum += array.get(i);
            if (sum > rightSum){
                rightSum = sum;
                maxRight = i;
            }
        }
        subarray.put("low", maxLeft);
        subarray.put("high", maxRight);
        subarray.put("sum", leftSum + rightSum);
        return subarray;
    }

    public int getLow(){
        return 0;
    }

    public int getHigh(){
        return array.size() - 1;
    }

    private ArrayList<Integer> array;
    private HashMap<String, Integer> subarray = new HashMap<String, Integer>();
    private HashMap<String, Integer> subarrayLeft = new HashMap<String, Integer>();
    private HashMap<String, Integer> subarrayRight = new HashMap<String, Integer>();
    private HashMap<String, Integer> subarrayCross = new HashMap<String, Integer>();
}

Python

findMaxSubarray.py

import sys

def findMaxSubarray(array, low, high):
        if low == high:
            subarray = {"low": low, "high": high, "sum": array[low]}
         return subarray
    else:
            mid = (low + high) / 2
        subarrayLeft = findMaxSubarray(array, low, mid)
            subarrayRight = findMaxSubarray(array, mid + 1, high)
            subarrayCross = findMaxCrossSubarray(array, low, mid, high)
            if subarrayLeft["sum"] > subarrayRight["sum"] and subarrayLeft["sum"] > subarrayCross["sum"]:
                    return subarrayLeft
            elif subarrayRight["sum"] > subarrayLeft["sum"] and subarrayRight["sum"] > subarrayCross["sum"]:
                    return subarrayRight
            else:
                    return subarrayCross 

def findMaxCrossSubarray(array, low, mid, high):
        sum = 0;
        leftSum = sys.maxint * -1
        maxLeft = 0
        for i in range(mid, low, -1):
            sum += array[i];
            if sum > leftSum :
                    leftSum = sum
                    maxLeft = i
        sum = 0;
        RightSum = sys.maxint * -1
        maxRight = 0
        for i in range(mid + 1, high):
            sum += array[i];
            if sum > RightSum :
                    RightSum = sum
                    maxRight = i
        crossSubArray = {"low": maxLeft, "high": maxRight, "sum": leftSum + RightSum}
        return crossSubArray

test.py

import findMaxSubarray

array = [13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7]
length = len(array) - 1
subarray = []
maxSubarray = findMaxSubarray.findMaxSubarray(array, 0, length)
print "The maximum of subarray is " + str(maxSubarray["sum"]) + \
        " from index " + str(maxSubarray["low"] + 1) + \
        " to index " + str(maxSubarray["high"] + 1) + "."
for i in range(maxSubarray["low"], maxSubarray["high"] + 1):
        subarray.append(array[i])
print "The elements of the maximum subarry are " + str(subarray) + "."

转载于:https://www.cnblogs.com/zhxbao/p/find_maximun_subarray.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值