LeetCode每日一题(689. Maximum Sum of 3 Non-Overlapping Subarrays)

博客讲述了如何解决寻找一个整数数组中长度为k的三段非重叠子数组,使得它们的和最大。通过构建数组w,计算w[i]到w[i+k-1]的和,然后计算前缀和left和后缀和right,分别存储最大值的索引。通过遍历找到最大和的三段子数组,并返回其起始索引。该方法避免了使用动态规划导致的时间复杂度过高问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Given an integer array nums and an integer k, find three non-overlapping subarrays of length k with maximum sum and return them.

Return the result as a list of indices representing the starting position of each interval (0-indexed). If there are multiple answers, return the lexicographically smallest one.

Example 1:

Input: nums = [1,2,1,2,6,7,5,1], k = 2
Output: [0,3,5]

Explanation: Subarrays [1, 2], [2, 6], [7, 5] correspond to the starting indices [0, 3, 5].
We could have also taken [2, 1], but an answer of [1, 3, 5] would be lexicographically larger.

Example 2:

Input: nums = [1,2,1,2,1,2,1,2,1], k = 2
Output: [0,2,4]

Constraints:

  • 1 <= nums.length <= 2 * 104
  • 1 <= nums[i] < 216
  • 1 <= k <= floor(nums.length / 3)

直接用 dp 来解会超时, 想了半天也没想到优化的办法。开始看答案。答案不难理解, 但是如果没有提示, 恐怕自己很难会往这个方向去想。

首先我们定义一个数组 w, w[i]代表从 nums[i]到 nums[i+k-1]的加和, 然后我们再对 w 做 prefix sum 和 suffix sum, 分别是 left 和 right, 这时要注意, 这两个 sum 中都是保存的最大值的 index, 也就是说 left[i]代表的是从 w[0]到 w[i]中最大值的 index, right[i]代表的是从 w[i]到 w[last]的最大值的 index, 无论是 left 还是 right, 相同的 w[i]值取相对小的 index。然后假设我们通过三个值,i, j, l, 将 w 分成三份, 那中间的 j 的取值范围就是 k < j < w.len() - k, 这时左边那部分的最大值就是 w[left[j-k]], 也就是从 w[0]到 w[j-k]中的最大值, 右边那部分的最大值是 w[right[j+k]], 也就是从 w[j+k]到 w[last]中的最大值, 中间部分的值是 w[j], 遍历 j, 每次将这三部分相加,取最大值即可



impl Solution {
    pub fn max_sum_of_three_subarrays(nums: Vec<i32>, k: i32) -> Vec<i32> {
        let mut w = vec![0; nums.len() - k as usize + 1];
        let mut queue: Vec<i32> = Vec::new();
        let mut sum = 0;
        for i in 0..nums.len() {
            queue.push(nums[i]);
            sum += nums[i];
            if queue.len() > k as usize {
                sum -= queue.remove(0);
            }
            if queue.len() == k as usize {
                w[i + 1 - k as usize] = sum;
            }
        }
        let mut max = 0;
        let mut left = vec![0; w.len()];
        for i in 0..w.len() {
            if w[i] > w[max] {
                max = i;
            }
            left[i] = max;
        }
        max = w.len() - 1;
        let mut right = vec![0; w.len()];
        for i in (0..w.len()).rev() {
            if w[i] >= w[max] {
                max = i;
            }
            right[i] = max;
        }
        let mut ans = Vec::new();
        let mut max = 0;
        for j in k as usize..w.len() - k as usize {
            if w[left[j - k as usize]] + w[j] + w[right[j + k as usize]] > max {
                max = w[left[j - k as usize]] + w[j] + w[right[j + k as usize]];
                ans = vec![left[j - k as usize] as i32, j as i32, right[j + k as usize] as i32];
            }
        }
        ans
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值