何为分治法?
   
在上一篇文章中讲到归并排序就有提到过分治法,这里在重复一次:
    
     分治法
    
   
分治法采用了递归的结构,将原问题分成几个规模较小但是类似于原问题的子问题, 通过递归的方式再来求解这些小问题,然后将子问题的解合并来建立原问题的解,分治法在每成递归时都有三个步骤:
- 
     
 分解:
 
 将原问题分解成若干个小问题,这些子问题是原问题的规模较小的实例
- 
     
 解决:
 
 解决这些子问题,通过递归的方式求解子问题,直到自问题的规模足够小,可以直接求解
- 
     
 合并:
 
 将这些子问题的解合并成原问题的解
    最大子序列和问题
   
比如说有一个数组:
4 , -3, 5, -2, -1, -1, 2, 6, -2
    对于这样一个数组,它的最大子序列和为11(从第一个元素到第七个)。
    
    对于任意一个栗子,可以发现最大子序列和只有三种情况:
   
- 出现在数组的左半部分
- 出现在数组的右半部分
- 出现在数组的中间部分,横跨左右两部分
    (这不是废话么=_=)
    
    而且对于左半部分或者右半部分,上述结论也成立,利用这特性,可以写出相应的递归,递归结束的条件是当只有一个元素时,判断这个元素是否大于零,大于零便返回这个数,否则返回零。
    
    然后求出左边最大值,右边最大值和横跨两边的最大值,返回这三个值中的最大值
    
    c语言代码如下:
   
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAX_N 20
int max3(int, int, int);
int maxSubArrayAns(int []);
int maxSubArray(int [], int, int);
int main(){
    int nums[MAX_N];
    int i;
    srand(time(0));
    printf("array: \n");
    for(int i = 0; i < MAX_N; i++){
        nums[i] = (int)(rand() % (MAX_N * 2) - MAX_N);
        printf("%d\t", nums[i]);
    }
    printf("\n");
    printf("The max subsequen sum is %d.\n", maxSubArrayAns(nums));
    return 0;
}
int max3(int a, int b, int c){
    if(a > b)
        return a > c ? a : c;
    else
        return b > c ? b : c;
}
int maxSubArray(int nums[], int left, int right){
    int maxLeftSum, maxRightSum;
    int maxLeftBorderSum, maxRightBorderSum;
    int leftBorderSum, rightBorderSum;
    if(left == right)
        if(nums[left] > 0)
            return nums[left];
        else
            return 0;
    int mid = (left + right) / 2, i;
    maxLeftSum = maxSubArray(nums, left, mid);
    maxRightSum = maxSubArray(nums, mid + 1, right);
    maxLeftBorderSum = 0, leftBorderSum = 0;
    for(i = mid; i >= left; i--){
        leftBorderSum += nums[i];
        if(leftBorderSum > maxLeftBorderSum)
            maxLeftBorderSum = leftBorderSum;
    }
    maxRightBorderSum = 0, rightBorderSum = 0;
    for(i = mid + 1; i <= right; i++){
        rightBorderSum += nums[i];
        if(rightBorderSum > maxRightBorderSum)
            maxRightBorderSum = rightBorderSum;
    }
    return max3(maxLeftSum, maxRightSum, maxLeftBorderSum + maxRightBorderSum);
}
int maxSubArrayAns(int nums[]){
    return maxSubArray(nums, 0, MAX_N - 1);
}使用分治法的话,平均时间复杂度为Θ(n lg n)。实际上解决最大子序列问题还有一种更加快速的方法,这种方法的时间复杂度是Θ(n),是一种线性的算法
int maxSubArrayAns(int nums[]){
    int i, thisSum = 0, maxSum = 0;
    for(i = 0; i < MAX_N - 1; i++){
        thisSum += nums[i];
        if(thisSum > maxSum)
            maxSum = thisSum;
        else if(thisSum < 0)
            thisSum = 0;
    }
    return maxSum;
} 
版权声明:本文为u014235934原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
