分治法 2

最大字数组问题

暴力解法

typedef struct {
    int leftIndex;
    int rightIndex;
    int maxSum;
} SubArrayData;

void maxSubArraySimple(int array[], int length, SubArrayData *subArrayData){
    int i =0;
    int j = 0;
    int currentSum = array[0];
    
    subArrayData->leftIndex = 0;
    subArrayData->rightIndex = 0;
    subArrayData->maxSum = array[0];
    
    for (i = 0; i < length; ++i){
        currentSum = 0;
        for (j = i; j < length; ++j){
            currentSum += array[j];
            if (currentSum > subArrayData->maxSum){
                subArrayData->leftIndex = i;
                subArrayData->rightIndex = j;
                subArrayData->maxSum = currentSum;
            }
        }
    }
}

算法基本过程:
遍历数组元素,以每一个数组元素为最大子数组第一个元素寻找子数组。

时间复杂度为 n^2

递归解法

typedef struct {
    int leftIndex;
    int rightIndex;
    int maxSum;
} SubArrayData;

void maxMidSubArray(int array[], int lowIndex, int highIndex, int midIndex, SubArrayData *subArrayData){
    int i = 0;
    int currentSum = 0;
    int leftMaxSum = array[midIndex];
    int rightMaxSum = array[midIndex + 1];
    subArrayData->leftIndex = midIndex;
    subArrayData->rightIndex = midIndex + 1;
    subArrayData->maxSum = array[midIndex];
    
    currentSum = 0;
    for (i = midIndex; i >= lowIndex; --i){
        currentSum += array[i];
        if (currentSum > leftMaxSum){
            leftMaxSum = currentSum;
            subArrayData->leftIndex = i;
        }
    }
    
    currentSum = 0;
    for (i = midIndex + 1; i <= highIndex; ++i){
        currentSum += array[i];
        if (currentSum > rightMaxSum){
            rightMaxSum = currentSum;
            subArrayData->rightIndex = i;
        }
    }
    
    subArrayData->maxSum = leftMaxSum + rightMaxSum;
}

void maxSubArray(int array[], int lowIndex, int highIndex, SubArrayData *subArrayData){
    int midIndex = 0;   
    SubArrayData rightMaxSubArrayData;
    SubArrayData midMaxSubArrayData;
    if (lowIndex < highIndex){
        midIndex = (lowIndex + highIndex) / 2;
        maxSubArray(array, lowIndex, midIndex, subArrayData);
        maxSubArray(array, midIndex + 1, highIndex, &rightMaxSubArrayData);
        maxMidSubArray(array, lowIndex, highIndex, midIndex, &midMaxSubArrayData);
        if (subArrayData->maxSum < rightMaxSubArrayData.maxSum){
            (*subArrayData) = rightMaxSubArrayData;
        }
        if (subArrayData->maxSum < midMaxSubArrayData.maxSum){
            (*subArrayData) = midMaxSubArrayData;
        }
    }else if (lowIndex == highIndex){
        subArrayData->leftIndex = lowIndex;
        subArrayData->rightIndex = lowIndex;
        subArrayData->maxSum = array[lowIndex];
    }

}

算法基本过程:
将待处理数组在中点分隔成两个子数组,最大子数组只可能在三个位置出现:

1 左边的子数组

2 右边的子数组

3 跨越中点的子数组

递归的查找这三个最大子数组,返回三者中最大的。

时间复杂度 nlg(n)

习题 4.1-5

时间复杂度 n^2

typedef struct {
    int leftIndex;
    int rightIndex;
    int maxSum;
} SubArrayData;

void question4_1_5(int array[], int length, SubArrayData *subArrayData){
    int i = 0;
    int j = 0;
    int leftMaxSum = 0;
    int rightMaxSum = 0;

    subArrayData->leftIndex = 0;
    subArrayData->rightIndex = 0;
    subArrayData->maxSum = array[0];

    for (i = 0; i < length - 1; ++i){
        leftMaxSum += array[i];
        if (leftMaxSum > subArrayData->maxSum){
            subArrayData->leftIndex = 0;
            subArrayData->rightIndex = i;
            subArrayData->maxSum = leftMaxSum;
        }

        rightMaxSum = 0;
        for (j = i + 1; j >=0; --j){
            rightMaxSum += array[j];
            if (rightMaxSum > subArrayData->maxSum){
                subArrayData->leftIndex = j;
                subArrayData->rightIndex = i + 1;
                subArrayData->maxSum = rightMaxSum;
            }
        }
    }

}

这个是按照题目给的过程写的,虽然算法是正确的,但是时间复杂度为 n^2 不符合要求,正确的做法是用空间换取时间。

时间复杂度 n

typedef struct {
    int leftIndex;
    int rightIndex;
    int maxSum;
} SubArrayData;

void question4_1_5(int array[], int length, SubArrayData *subArrayData){
    int i = 0;
    SubArrayData maxSubArrays[length];
    
    maxSubArrays[0].leftIndex = 0;
    maxSubArrays[0].rightIndex = 0;
    maxSubArrays[0].maxSum = array[0];
    
    for (i = 1; i < length; ++i){
        if (maxSubArrays[i - 1].maxSum < 0){
            maxSubArrays[i].leftIndex = i;
            maxSubArrays[i].rightIndex = i;
            maxSubArrays[i].maxSum = array[i];
        }else {
            maxSubArrays[i].leftIndex = maxSubArrays[i - 1].leftIndex;
            maxSubArrays[i].rightIndex = i;
            maxSubArrays[i].maxSum = maxSubArrays[i - 1].maxSum + array[i];
        }
    }
    
    (*subArrayData) = maxSubArrays[0];
    
    for (i = 0; i < length; ++i){
        if (subArrayData->maxSum < maxSubArrays[i].maxSum){
            (*subArrayData) = maxSubArrays[i];
        }
    }
}

这个是正确的解法,算法维护了一个数组,这个数组储存这从起点到索引为 i 的数组的最大子数组,最后从这些最大子数组中找到那个最大的即为整个数组的最大子数组。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1. 链表 链表是最基本的数据结构,面试官也常常用链表来考察面试者的基本能力,而且链表相关的操作相对而言比较简单,...
    Mr希灵阅读 5,316评论 0 20
  • 1 序 2016年6月25日夜,帝都,天下着大雨,拖着行李箱和同学在校门口照了最后一张合照,搬离寝室打车去了提前租...
    RichardJieChen阅读 10,612评论 0 12
  • 分治策略 本文包括分治的基本概念二分查找快速排序归并排序找出伪币棋盘覆盖最大子数组 源码链接:https://gi...
    廖少少阅读 5,882评论 0 7
  • 文|孤小狐 听说阿东和小果结婚了。他们都是我的朋友,分分合合七年,所以我一点都不惊讶。 阿东和小果的恋情说来话长。...
    我是孤小狐阅读 3,746评论 0 1
  • 文:半夏 11月17日上午,县教研室周伟主任和张灿义老师在中心校单主任和宋主任...
    llz半夏阅读 4,645评论 0 0