• 求解最大子数组问题 -- 暴力求解 和 分治法求解


    /*------------------  求解最大子数组问题  ---------------
        最大子数组,就是求解一个数组的所有元素的各种组合中,和最大的
    那个子数组。在这种情况下,如果元素值全部非负,那么最大子数组当然
    是所有元素。但是如果有负值的元素存在,那么久需要找到一个由数组中
    连续几个元素组成的子数组并且其元素值之和最大。
    */
    #include <iostream>
    using namespace std;
    
    struct ArrayStruct {
        ArrayStruct(int b = 0, int e = 0, int s = 0):
                    begin(b), end(e), sum(s) { }
        int begin;
        int end;
        int sum;
    };
    
    /*
    方法一: 首先,最简单的当然是暴力求解,这种情况下,算法的复杂度是
    ø(n^2)的,代码如函数 subArrayRough 所示。 
    */
    ArrayStruct subArrayRough(int *array, int length) {
        int sum = -999999;
        int begin, end;
        for (int i = 0; i != length; ++i) {
            int sumTemp = 0;
            for (int j = i; j != length; ++j) {
                sumTemp += array[j];
                if (sum < sumTemp) {
                    begin = i;
                    sum = sumTemp;
                    end = j;
                }
            }
        }
        return ArrayStruct(begin, end, sum);
    }
    
    /*
    方法二是采用分治法:
        加入我们寻找数组 A[low, high] 的最大子数组,使用分治技术意味着
    把原数组进行分割,也就是将原数组划分为规模尽量相同的子数组。那么,就需
    要找到原数组的重点 mid,然后分别对原数组的 mid 左边和右边进行处理。
    那么,最大子数组所处的位置必然是下面三种情况之一【i, j 为结果范围下标】:
        · 完全位于子数组 A[low, mid]中,因此 low <= i <= j <= mid.
        · 完全位于子数组A[mid + 1, high] 中,因此 mid < i <= j <= high.
        · 跨越中点,因此 low <= i <= mid < j <= high
    实际上,数组 A 的最大子数组必然是上面三种情况中的最大者。那么,我们只需要找
    到上面三种情况的最大者即可。
        那么,我们就可以递归地求解子数组 A[low, mid],A[mid + 1, high] 的最大
    子数组,因为这仍然是求解最大子数组问题,然后将这两者的值和两者和中点组成的组数组
    三者中寻找最大值。那么,我们就要处理三种情况,A[low, mid],A[mid + 1, high] 和
    包括中点三种情况。伪代码如下:
    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-MAXIMUM-CROSSING-SUBARRAY(A, low, mid, high)
            if left-sum >= right-sum && left-sum >= cross-sum:
                return (left-low, left-high, left-sum)
            if right-sum >= right-sum && right-sum >= cross-sum:
                return (right-low, right-high, right-sum)
            else
                return (cross-low, cross-high, cross-sum)
    
    其中,函数 FIND-MAXIMUM-CROSSING-SUBARRAY 的伪代码如下,其实它的作用就是找出一定包含 mid 元素的
    的最大子数组,那么久可以直接从 mid 出发去向两边查找:
    FIND-MAXIMUM-CROSSING-SUBARRAY(A, low, mid, high):
        left-sum = -∞
        sum = 0;
        for i = mid downto low:
            sum += A[i]
            if left-sum < sum:
                left-sum = sum
                max-left = i
        right-sum = -∞
        sum = 0;
        for i = mid + 1 to high:
            sum += A[i]
            if right-sum < sum:
                right-sum = sum
                max-right = i
        return (max-left , max- right, left-sum + right-sum)
    
    根据伪代码不难写出代码。
    
    FIND-MAXIMUM-CROSSING-SUBARRAY 的时间复杂度是线性的,而 FIND-MAXIMUM-SUBARRAY
    因为是分治法,对于分治法算时间复杂度的主方法 T(n) = aT(n / b) + f(n) 可以知道,因为
    a == b == 2 所以时间复杂度是 log(n),所以总的时间复杂度是 n(log(n))
    */
    
    ArrayStruct findMaximumCrossingSubArray(int *array, int low, int mid, int high) {
        int leftSum = -99999;
        int sum = 0, leftMax = low;
        for (int i = mid; i >= 0; --i) {
            sum += array[i];
            if (sum > leftSum) {
                leftSum = sum;
                leftMax = i;
            }
        }
    
        int rightSum = -99999;
        sum = 0;
        int rughtMax = high;
        for (int i = mid + 1; i <= high; ++i) {
            sum += array[i];
            if (sum > rightSum) {
                rightSum = sum;
                rughtMax = i;
            }
        }
        return ArrayStruct(leftMax, rughtMax, leftSum + rightSum);
    }
    
    ArrayStruct findMaximumSubArray(int *array, int low, int high) {
        if (high == low) {
            return ArrayStruct(low, high, array[low]);
        } else {
            int mid = (low + high) / 2;
            ArrayStruct left = findMaximumSubArray(array, low, mid);
            ArrayStruct right = findMaximumSubArray(array, mid + 1, high);
            ArrayStruct cross = findMaximumCrossingSubArray(array, low, mid, high);
    
            if (left.sum >= right.sum && left.sum >= cross.sum)
                return left;
            else if (right.sum >= right.sum && right.sum >= cross.sum)
                return right;
            else
                return cross;
        }
    }
    
    int main(int argc, char const *argv[])
    {
        cout << "Input the size of the array: ";
        int arraySize;
        int *array;
        cin >> arraySize;
        array = new int[arraySize];
        for (int i = 0; i != arraySize; ++i)
            cin >> array[i];
        ArrayStruct a = subArrayRough(array, arraySize);
        cout << "result of rough found: " << endl << '	';
        for(int i = a.begin; i <= a.end; ++i) {
            cout << array[i] << " ";
        }
        cout << endl;
        cout << "result of minute found: " << endl << '	';
        ArrayStruct b = findMaximumSubArray(array, 0, arraySize - 1);
        for(int i = b.begin; i <= b.end; ++i) {
            cout << array[i] << " ";
        }
        cout << endl;
    
        return 0;
    }
  • 相关阅读:
    操作系统笔记------处理机调度
    操作系统笔记------进程同步(3)
    体系结构笔记------动态调度中的Tomasulo算法
    体系结构笔记------动态分支预测
    体系结构笔记------MIPS流水线的简单实现
    远程使用内网服务器的tensorboard和jupyter notebook
    tensorflow多分类标签转换成onehot
    anaconda的虚拟环境下,安装和管理python包的方法
    雪伦面经
    tensorflow官方MNIST数据集导入错误解决办法
  • 原文地址:https://www.cnblogs.com/xiezhw3/p/4069809.html
Copyright © 2020-2023  润新知