算法导论学习笔记(一):分治策略

转载请注明原作者 @yoshino,强烈要求支持TOC目录和数学公式的输入!
更新不及时,有空慢慢写吧,原文是写在Bear上粘贴来的,可能格式有点乱。
具体的工程在我的github上。


所谓的分治策略就是将问题分解成几个相同的小问题,解决小问题再递归回大问题。步骤可以分为三步:

  • 分解(Divide):将原问题划分为若干个子问题,保证子问题和原问题的一致,只是规模更小。
  • 解决(Conquer):递归地求解出子问题,若子问题的规模足够小,则直接求解。
  • 合并(Combine):将子问题的解合并成原问题的解。

最大子数组问题

  • 问题描述:给定一个数组,求其中子数组的最大和,采用分治策略进行解决。
  • 问题分析:我们把此数组看作A[low,high],我们将要用分治法求出其最大的子数组。使用分治法意味着我们要将数组划分为两个规模尽量相等的子数组,找到数组的中央位置,比如mid,然后考虑求解两个子数组A[low,mid]和A[mid+1,high]。那么子数组A[i,j]所有的情况都逃脱不了一下三种:
    1. 完全位于子数组A[low,mid]中,low<=i<=j<=mid
    2. 完全位于子数组A[mid+1,high]中,mid 3. 跨越了中点,因此low<=i<=mid 那么我们可以递归的求解A[low,mid]和A[mid+1,high]的最大子数组,因为这两个子问题仍是最大数组问题,只是规模更小。因此剩下的工作就是寻找跨越中点的最大子数组,然后在三者中选取最大者。
  • 参考资料来自分治算法-最大子数组问题,作者:爱国者002
  • java代码实现:
public int[] getMaxSubArray(int[] num, int low, int high) {
        if (low == high) return num;
        int mid = (low + high) / 2;
        int[] left = new int[3];
        int[] right = new int[3];
        int[] cross = new int[3];
        left = getMaxSubArray(num, low, mid);
        right = getMaxSubArray(num, mid + 1, high);
        cross = getMaxCrossMid(num, low, high, mid);
        if (left[2] >= right[2] && left[2] >= cross[2]) {
            return left;
        } else if (right[2] >= left[2] && right[2] >= cross[2]) {
            return right;
        } else {
            return cross;
        }
    }

    private int[] getMaxCrossMid(int[] num, int low, int high, int mid) {
        int leftSum = Integer.MIN_VALUE;
        int sum = 0; // 保存和的
        int left = 0; // 记录左边位置
        for (int i = mid; i >= low; i--) {
            sum = sum + num[i];
            if (sum > leftSum) { // 证明所加数字为正数,那么符合条件(因为最大子数组内正数越多指定越大)
                leftSum = sum;
                left = i;
            }
        }
        int rightSum = Integer.MIN_VALUE;
        int sum2 = 0;
        int right = 0; // 记录右边位置
        for (int i = mid + 1; i <= high; i++) {
            sum2 = sum2 + num[i];
            if (sum2 > rightSum) {
                rightSum = sum2;
                right = i;
            }
        }
        int[] result = new int[3];
        result[0] = left;
        result[1] = right;
        result[2] = leftSum + rightSum;
        return result;
    }

你可能感兴趣的:(算法导论学习笔记(一):分治策略)