LeetCode 3473: Sum of K Subarrays With Length at Least M (Dynamic Programming / Prefix Sum)
LeetCode 3473DPPrefix SumToday we solve LeetCode 3473 - Sum of K Subarrays With Length at Least M.
Source: https://leetcode.com/problems/sum-of-k-subarrays-with-length-at-least-m/
English
Problem Summary
Pick exactly k non-overlapping subarrays, each with length at least m, and maximize their total sum.
Key Insight
Use prefix sums and DP. Let dp[t][i] be the best sum using first i numbers with t segments. Transition with a rolling best term dp[t-1][j]-pre[j] where j <= i-m.
Complexity Analysis
Time: O(nk)
Space: O(n) with rolling arrays.
Reference Implementations (Java / Go / C++ / Python / JavaScript)
class Solution {
public int maxSum(int[] nums, int k, int m) {
int n = nums.length;
long[] pre = new long[n + 1];
for (int i = 0; i < n; i++) pre[i + 1] = pre[i] + nums[i];
long NEG = Long.MIN_VALUE / 4;
long[] dpPrev = new long[n + 1];
java.util.Arrays.fill(dpPrev, NEG);
dpPrev[0] = 0;
for (int seg = 1; seg <= k; seg++) {
long[] dpCur = new long[n + 1];
java.util.Arrays.fill(dpCur, NEG);
long best = NEG;
for (int i = 1; i <= n; i++) {
dpCur[i] = dpCur[i - 1];
if (i - m >= 0 && dpPrev[i - m] > NEG / 2) {
best = Math.max(best, dpPrev[i - m] - pre[i - m]);
}
if (best > NEG / 2) {
dpCur[i] = Math.max(dpCur[i], pre[i] + best);
}
}
dpPrev = dpCur;
}
return (int) dpPrev[n];
}
}func maxSum(nums []int, k int, m int) int {
n := len(nums)
pre := make([]int64, n+1)
for i, x := range nums {
pre[i+1] = pre[i] + int64(x)
}
const NEG int64 = -1 << 60
prev := make([]int64, n+1)
for i := 1; i <= n; i++ { prev[i] = NEG }
for seg := 1; seg <= k; seg++ {
cur := make([]int64, n+1)
for i := range cur { cur[i] = NEG }
best := NEG
for i := 1; i <= n; i++ {
cur[i] = cur[i-1]
if i-m >= 0 && prev[i-m] > NEG/2 {
cand := prev[i-m] - pre[i-m]
if cand > best { best = cand }
}
if best > NEG/2 {
cand := pre[i] + best
if cand > cur[i] { cur[i] = cand }
}
}
prev = cur
}
return int(prev[n])
}class Solution {
public:
int maxSum(vector<int>& nums, int k, int m) {
int n = nums.size();
vector<long long> pre(n + 1, 0);
for (int i = 0; i < n; ++i) pre[i + 1] = pre[i] + nums[i];
const long long NEG = LLONG_MIN / 4;
vector<long long> prev(n + 1, NEG), cur(n + 1, NEG);
prev[0] = 0;
for (int seg = 1; seg <= k; ++seg) {
fill(cur.begin(), cur.end(), NEG);
long long best = NEG;
for (int i = 1; i <= n; ++i) {
cur[i] = cur[i - 1];
if (i - m >= 0 && prev[i - m] > NEG / 2) best = max(best, prev[i - m] - pre[i - m]);
if (best > NEG / 2) cur[i] = max(cur[i], pre[i] + best);
}
swap(prev, cur);
}
return (int)prev[n];
}
};class Solution:
def maxSum(self, nums: list[int], k: int, m: int) -> int:
n = len(nums)
pre = [0] * (n + 1)
for i, x in enumerate(nums):
pre[i + 1] = pre[i] + x
NEG = -10**30
dp_prev = [NEG] * (n + 1)
dp_prev[0] = 0
for _ in range(1, k + 1):
dp_cur = [NEG] * (n + 1)
best = NEG
for i in range(1, n + 1):
dp_cur[i] = dp_cur[i - 1]
if i - m >= 0 and dp_prev[i - m] > NEG // 2:
best = max(best, dp_prev[i - m] - pre[i - m])
if best > NEG // 2:
dp_cur[i] = max(dp_cur[i], pre[i] + best)
dp_prev = dp_cur
return dp_prev[n]function maxSum(nums, k, m) {
const n = nums.length;
const pre = Array(n + 1).fill(0);
for (let i = 0; i < n; i++) pre[i + 1] = pre[i] + nums[i];
const NEG = -1e30;
let prev = Array(n + 1).fill(NEG);
prev[0] = 0;
for (let seg = 1; seg <= k; seg++) {
const cur = Array(n + 1).fill(NEG);
let best = NEG;
for (let i = 1; i <= n; i++) {
cur[i] = cur[i - 1];
if (i - m >= 0 && prev[i - m] > NEG / 2) {
best = Math.max(best, prev[i - m] - pre[i - m]);
}
if (best > NEG / 2) cur[i] = Math.max(cur[i], pre[i] + best);
}
prev = cur;
}
return prev[n];
}中文
题目概述
选择恰好 k 个互不重叠的子数组,每个子数组长度至少为 m,使总和最大。
核心思路
前缀和 + 动态规划。定义 dp[t][i] 表示前 i 个数里选 t 段的最大和。转移时维护滚动最优项 dp[t-1][j]-pre[j](其中 j <= i-m),即可在线更新。
复杂度分析
时间复杂度:O(nk)
空间复杂度:O(n)(滚动数组)。
多语言参考实现(Java / Go / C++ / Python / JavaScript)
class Solution {
public int maxSum(int[] nums, int k, int m) {
int n = nums.length;
long[] pre = new long[n + 1];
for (int i = 0; i < n; i++) pre[i + 1] = pre[i] + nums[i];
long NEG = Long.MIN_VALUE / 4;
long[] dpPrev = new long[n + 1];
java.util.Arrays.fill(dpPrev, NEG);
dpPrev[0] = 0;
for (int seg = 1; seg <= k; seg++) {
long[] dpCur = new long[n + 1];
java.util.Arrays.fill(dpCur, NEG);
long best = NEG;
for (int i = 1; i <= n; i++) {
dpCur[i] = dpCur[i - 1];
if (i - m >= 0 && dpPrev[i - m] > NEG / 2) {
best = Math.max(best, dpPrev[i - m] - pre[i - m]);
}
if (best > NEG / 2) {
dpCur[i] = Math.max(dpCur[i], pre[i] + best);
}
}
dpPrev = dpCur;
}
return (int) dpPrev[n];
}
}func maxSum(nums []int, k int, m int) int {
n := len(nums)
pre := make([]int64, n+1)
for i, x := range nums {
pre[i+1] = pre[i] + int64(x)
}
const NEG int64 = -1 << 60
prev := make([]int64, n+1)
for i := 1; i <= n; i++ { prev[i] = NEG }
for seg := 1; seg <= k; seg++ {
cur := make([]int64, n+1)
for i := range cur { cur[i] = NEG }
best := NEG
for i := 1; i <= n; i++ {
cur[i] = cur[i-1]
if i-m >= 0 && prev[i-m] > NEG/2 {
cand := prev[i-m] - pre[i-m]
if cand > best { best = cand }
}
if best > NEG/2 {
cand := pre[i] + best
if cand > cur[i] { cur[i] = cand }
}
}
prev = cur
}
return int(prev[n])
}class Solution {
public:
int maxSum(vector<int>& nums, int k, int m) {
int n = nums.size();
vector<long long> pre(n + 1, 0);
for (int i = 0; i < n; ++i) pre[i + 1] = pre[i] + nums[i];
const long long NEG = LLONG_MIN / 4;
vector<long long> prev(n + 1, NEG), cur(n + 1, NEG);
prev[0] = 0;
for (int seg = 1; seg <= k; ++seg) {
fill(cur.begin(), cur.end(), NEG);
long long best = NEG;
for (int i = 1; i <= n; ++i) {
cur[i] = cur[i - 1];
if (i - m >= 0 && prev[i - m] > NEG / 2) best = max(best, prev[i - m] - pre[i - m]);
if (best > NEG / 2) cur[i] = max(cur[i], pre[i] + best);
}
swap(prev, cur);
}
return (int)prev[n];
}
};class Solution:
def maxSum(self, nums: list[int], k: int, m: int) -> int:
n = len(nums)
pre = [0] * (n + 1)
for i, x in enumerate(nums):
pre[i + 1] = pre[i] + x
NEG = -10**30
dp_prev = [NEG] * (n + 1)
dp_prev[0] = 0
for _ in range(1, k + 1):
dp_cur = [NEG] * (n + 1)
best = NEG
for i in range(1, n + 1):
dp_cur[i] = dp_cur[i - 1]
if i - m >= 0 and dp_prev[i - m] > NEG // 2:
best = max(best, dp_prev[i - m] - pre[i - m])
if best > NEG // 2:
dp_cur[i] = max(dp_cur[i], pre[i] + best)
dp_prev = dp_cur
return dp_prev[n]function maxSum(nums, k, m) {
const n = nums.length;
const pre = Array(n + 1).fill(0);
for (let i = 0; i < n; i++) pre[i + 1] = pre[i] + nums[i];
const NEG = -1e30;
let prev = Array(n + 1).fill(NEG);
prev[0] = 0;
for (let seg = 1; seg <= k; seg++) {
const cur = Array(n + 1).fill(NEG);
let best = NEG;
for (let i = 1; i <= n; i++) {
cur[i] = cur[i - 1];
if (i - m >= 0 && prev[i - m] > NEG / 2) {
best = Math.max(best, prev[i - m] - pre[i - m]);
}
if (best > NEG / 2) cur[i] = Math.max(cur[i], pre[i] + best);
}
prev = cur;
}
return prev[n];
}
Comments