vlambda博客
学习文章列表

Go-最大子数组问题

最大子数组问题

问题描述: 寻找数组A[1..n]和最大的非空连续子数组。

  • 条件: 数组中必须含有负数,不然将毫无意义,因为最大子数组将就是数组A本身。
  • 思想:分治思想。
    • a: 完全位于A[low, mid]; 此时 low <= i <= j <= mid
    • b: 完全位于A[mid+1, high]中,此时 mid + 1 <= i <= j <= high
    • c: 跨越了中点mid, 此时 low <= i  <= mid < j < high
    • 假设我们要求A的子数组A[low, high]的最大子数组。根据分治策略,我们先将A[low,high] 平分
    • 那么 A[low,highj]的子数组A[i,j]只有三种可能
    • 对于 a 和 b 情况,仍然是最大子数组问题,可递归求解。
    • 只需要计算 c 类情况。
  • 步骤
    • 计算 c 类情况
/** * @title findMaxCrossingSubarray * @description 寻找最大子数组问题中的寻找过中点的最大子数组函数 * 总体理念: 对于给定的数组, 其中点坐标mid, 即向左寻找到最大子数组和, 再向右寻找到最大子数组, 返回左右边界及整个数组即可 * 空间复杂度: O(n) * 时间复杂度: O(n) * @auth: ncuwen * @param: A 原数组 * @param: low 数组起始下标 * @param: high 数组末尾下标 * @param: mid 数组中点下标, 有 low <= mid <= high * @return: 返回一个下标元组划分跨越中点的最大子数组的边界, 并返回最大子数组中值的和 */func findMaxCrossingSubarray(A []int, low int, mid int, high int) (int, int, int) { leftSum := constants.INT_MIN maxLeft := mid sum := 0 for i := mid; i >= low; i-- { sum += A[i] if sum > leftSum { leftSum = sum maxLeft = i } } rightSum := constants.INT_MIN maxRight := mid + 1 sum = 0 for j := mid + 1; j <= high; j++ { sum += A[j] if sum > rightSum { rightSum = sum maxRight = j } } return maxLeft, maxRight, leftSum + rightSum}
  • 求解最大子数组问题的分治算法
/** * @title FindMaxSubarray * @description 寻找最大子数组 * 总体理念: 分治思想 * 空间复杂度: O(n) * 时间复杂度: O(nlg(n)) * @auth: ncuwen * @param: A 原数组 * @param: low 数组起始下标 * @param: high 数组末尾下标 */func FindMaxSubarray(A []int, low int, high int) (int, int, int){ if high == low { return low, high, A[low] } else { mid := (low + high) / 2 leftLow, leftHigh, leftSum := FindMaxSubarray(A, low, mid) rightLow, rightHigh, rightSum := FindMaxSubarray(A, mid + 1, high) crossLow, crossHigh, crossSum := findMaxCrossingSubarray(A, low, mid, high) if leftSum >= rightSum && leftSum >= crossSum { return leftLow, leftHigh, leftSum } else { if rightSum >= crossSum { return rightLow, rightHigh, rightSum } else { return crossLow, crossHigh, crossSum } } }}