《算法导论》@读书笔记@ 第四章 - 最大子数组(包含js版代码实现)

在这里插入图片描述

最大子数组问题介绍

算法导论上举了一个例子
在这里插入图片描述
在这里插入图片描述

实际上问题就是 寻找数组A的最大非空连续子数组

算法思路

分治法
假设将原数组一分为2的话,我们要寻找的最大子数组他所处的位置只有三种情况
1.最大子数组完全在左边
在这里插入图片描述

2.最大子数组完全在右边
在这里插入图片描述

3.最大子数组穿越左边和右边
在这里插入图片描述

然后我们只要比较这三个和的大小就可以知道最大的是哪一组了

算法过程

假定一个求解方法findMaxSubarray,
求解左边最大子数组findMaxSubarray(left)
求解右边最大子数组findMaxSubarray(right)
我们还需要一个求得最大交叉数组的方法findMaxCrossingSubarray

过程如下图所示 从中间分别往两边遍历累加,分别记住两边和最大的位置然后在合并得到的就是交叉最大子数组
在这里插入图片描述

算法实现

javascript版本

function findMaxCrossingSubarray(left, right) {
    
    
    const L = left.length
    const R = right.length
    let sum = left[L - 1]
    let leftSum = left[L - 1], rightSum = right[0]
    let maxLeft = L-1
    let maxRight = 0
    for (let i = L - 2; i >= 0; i--) {
    
    
        sum = left[i] + sum
        if (leftSum < sum) {
    
    
            leftSum = sum
            maxLeft = i
        }
    }
    sum = right[0]
    for (let j = 1; j < R; j++) {
    
    
        sum = right[j] + sum
        if (rightSum < sum) {
    
    
            rightSum = sum
            maxRight = j
        }
    }
    return [left.slice(maxLeft, L).concat(right.slice(0, maxRight + 1)), leftSum + rightSum]
}
function findMaxSubarray(arr) {
    
    
    let newArr = [...arr]
    let len = newArr.length
    if (len < 2) return [newArr, newArr[0]]
    let middle = Math.floor(len / 2)
    let left = newArr.slice(0, middle)
    let right = newArr.slice(middle, len)
    let [leftArr, leftSum] = findMaxSubarray(left)
    let [rightArr, rightSum] = findMaxSubarray(right)
    let [crossArr, crossSum] = findMaxCrossingSubarray(left, right)
    if (leftSum >= rightSum && leftSum >= crossSum) {
    
    
        return [leftArr, leftSum]
    } else if (rightSum >= leftSum && rightSum >= crossSum) {
    
    
        return [rightArr, rightSum]
    } else {
    
    
        return [crossArr, crossSum]
    }
}
module.exports = findMaxSubarray

猜你喜欢

转载自blog.csdn.net/weixin_38616850/article/details/110127987