【LeetCode】689、三个无重叠子数组的最大和

【LeetCode】689、三个无重叠子数组的最大和


一、dp

1.1 dp

// go
// 输入: nums[]
// 计算: 找三段长度为 k 的不重叠的子数组. 要求这 3k 个元素之和最大
// 输出: 三段子数组的 起始位置. 若有多个结果, 返回字典序最小的一个
func maxSumOfThreeSubarrays(nums []int, k int) []int {
    // 整体思路: 枚举 中间, 在左取长k的最大累加和子数组, 在右取长k的最大累加和子数组

    // 基础数据
    n := len(nums)
    sums := make([]int, n) // sums[i]: 起点为i, 长度为k, 的数组的累加和. 构造方式: 定长滑窗
    sum := 0 // 临时变量, 每一步的累加和
    for l, r := 0, 0; r < n; r++ {
        sum += nums[r]
        if r-l+1==k {
            sums[l] = sum
            sum -= nums[l]
            l++
        }
    }

    prefix := make([]int, n) // prefix[i]: [0..i]范围, 长k的 最大累加和 子数组, 的起始位置
    prefix[k-1] = 0 // 初始值
    l, r := 1, k // [l...r] 是长度为k的子数组
    for r < n {
        if sums[l] > sums[prefix[r-1]] { // 对应prefix[r-1]第一次遇到的值就是初始值prefix[r-1]
            // > 是为了同样最大累加和情况下, 最小的字典序
            prefix[r] = l
        } else {
            prefix[r] = prefix[r-1]
        }
        l++; r++
    }

    suffix := make([]int, n) // suffix[i]: [i..n-1]范围, 长k的 最大累加和 子数组, 的起始位置
    suffix[n-k] = n-k // 初始值
    for l := n-k-1; l >= 0; l-- {
        if sums[l] >= sums[suffix[l+1]] { // 对应suffix[l+1]第一次遇到的值就是初始值suffix[n-k]
            // >= 是为了同样最大累加和情况下, 最小的字典序
            suffix[l] = l
        } else {
            suffix[l] = suffix[l+1]
        }
    }

    // 枚举 中间, 在左右分别取 最大的. 选各情况中最大的
    // 0..i..j..n-1
    //  左  中  右
    i := k
    j := 2*k-1 // [i...j] 就是中间那个长度为k的子数组
    mx := 0 // 临时变量, 整体3k长度的 最大累加和
    a, b, c := 0, 0, 0 // 三个子数组的起点
    for j < n-k {
        // 0...i-1  i...j   j+1...n-1
        //  起点p    i开头     起点s
        p, s := prefix[i-1], suffix[j+1]
        sum := sums[p] + sums[i] + sums[s]
        if sum > mx {
            mx = sum
            a, b, c = p, i, s
        }
        i++; j++
    }
    return []int{a, b, c}
}

【算法讲解071【必备】子数组最大累加和问题与扩展-下】

二、多语言解法

C p p / G o / P y t h o n / R u s t / J s / T s Cpp/Go/Python/Rust/Js/Ts Cpp/Go/Python/Rust/Js/Ts

// cpp
// go 同上
# python
// rust
// js
// ts
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

呆呆的猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值