Given an integer array arr[] and an integer k, partition the array into contiguous subarrays such that each subarray has a length of at most k. After partitioning, replace every element in each subarray with the maximum element present in that subarray.
Compute the maximum possible sum of the array after performing this operation.
Input: arr = [4, 1, 2, 3], k = 2
Output: 14
Explanation: One optimal partition is [4, 1] and [2, 3]. Therefore, the maximum possible sum will be 4 + 4 + 3 + 3 = 14.Input: arr[] = [2, 2], k = 1
Output: 4
Explanation: The array is partitioned as [2] and [2]. Hence, the sum is 2 + 2 = 4.Input: arr[] = [4, 6, 1, 1, 1], k = 2
Output: 18
Explanation: One optimal partition is [4], [6, 1] and [1, 1], Therefore, the maximum possible sum will be 4 + 6 + 6 + 1 + 1 = 18.
Table of Content
[Naive Approach] - Using Recursion - O(k^n) Time and O(n) Space
The idea is to try all possible partitions starting from the current index. For each partition of length from 1 to k, we keep track of the maximum element in that partition. Since every element in the partition is replaced by this maximum value, its contribution becomes maximum element × partition length. We then recursively solve the remaining array and take the maximum sum among all possible partition choices.
#include<iostream>
#include<vector>
using namespace std;
// Returns the maximum sum obtainable starting from index i
int maxSumRec(vector<int>& arr, int i, int k) {
int n = arr.size();
// No elements left to partition
if (i == n)
return 0;
int maxVal = 0;
int ans = 0;
// Try all valid partition lengths starting at i
for (int j = i; j < min(n, i + k); j++) {
maxVal = max(maxVal, arr[j]);
int len = j - i + 1;
ans = max(ans, maxVal * len + maxSumRec(arr, j + 1, k));
}
return ans;
}
// Returns the maximum possible sum after partitioning arr[]
int maxPartitionSum(vector<int>& arr, int k) {
return maxSumRec(arr, 0, k);
}
int main() {
vector<int> arr = {4, 1, 2, 3};
int k = 2;
cout << maxPartitionSum(arr, k) << endl;
return 0;
}
public class GfG {
// Returns the maximum sum obtainable starting from index i
static int maxSumRec(int[] arr, int i, int k) {
int n = arr.length;
// No elements left to partition
if (i == n)
return 0;
int maxVal = 0;
int ans = 0;
// Try all valid partition lengths starting at i
for (int j = i; j < Math.min(n, i + k); j++) {
maxVal = Math.max(maxVal, arr[j]);
int len = j - i + 1;
ans = Math.max(ans, maxVal * len + maxSumRec(arr, j + 1, k));
}
return ans;
}
// Returns the maximum possible sum after partitioning arr[]
static int maxPartitionSum(int[] arr, int k) {
return maxSumRec(arr, 0, k);
}
public static void main(String[] args) {
int[] arr = {4, 1, 2, 3};
int k = 2;
System.out.println(maxPartitionSum(arr, k));
}
}
# Returns the maximum sum obtainable starting from index i
def maxSumRec(arr, i, k):
n = len(arr)
# No elements left to partition
if i == n:
return 0
maxVal = 0
ans = 0
# Try all valid partition lengths starting at i
for j in range(i, min(n, i + k)):
maxVal = max(maxVal, arr[j])
length = j - i + 1
ans = max(ans, maxVal * length + maxSumRec(arr, j + 1, k))
return ans
# Returns the maximum possible sum after partitioning arr[]
def maxPartitionSum(arr, k):
return maxSumRec(arr, 0, k)
if __name__ == "__main__":
arr = [4, 1, 2, 3]
k = 2
print(maxPartitionSum(arr, k))
using System;
class GfG {
// Returns the maximum sum obtainable starting from index i
static int MaxSumRec(int[] arr, int i, int k) {
int n = arr.Length;
// No elements left to partition
if (i == n)
return 0;
int maxVal = 0;
int ans = 0;
// Try all valid partition lengths starting at i
for (int j = i; j < Math.Min(n, i + k); j++) {
maxVal = Math.Max(maxVal, arr[j]);
int len = j - i + 1;
ans = Math.Max(ans, maxVal * len + MaxSumRec(arr, j + 1, k));
}
return ans;
}
// Returns the maximum possible sum after partitioning arr[]
static int MaxPartitionSum(int[] arr, int k) {
return MaxSumRec(arr, 0, k);
}
static void Main() {
int[] arr = {4, 1, 2, 3};
int k = 2;
Console.WriteLine(MaxPartitionSum(arr, k));
}
}
// Returns the maximum sum obtainable starting from index i
function maxSumRec(arr, i, k) {
const n = arr.length;
// No elements left to partition
if (i === n)
return 0;
let maxVal = 0;
let ans = 0;
// Try all valid partition lengths starting at i
for (let j = i; j < Math.min(n, i + k); j++) {
maxVal = Math.max(maxVal, arr[j]);
const len = j - i + 1;
ans = Math.max(ans, maxVal * len + maxSumRec(arr, j + 1, k));
}
return ans;
}
// Returns the maximum possible sum after partitioning arr[]
function maxPartitionSum(arr, k) {
return maxSumRec(arr, 0, k);
}
// Driver code
const arr = [4, 1, 2, 3];
const k = 2;
console.log(maxPartitionSum(arr, k));
Output
14
[Expected Approach] - Using Dynamic Programming – O(n^2) Time and O(n) Space
The recursive solution recalculates many subproblems multiple times. This can be optimized using Dynamic Programming. Define a DP array dp[] where dp[i] represents the maximum sum achievable using the first i elements. For each position i, consider partitions ending at index i - 1 with size at most k. While expanding the partition backwards, maintain the maximum element in the partition and update the best possible value.
Steps:
- Create a DP array dp of size n + 1, where dp[i] represents the maximum sum obtainable using the first i elements.
- Iterate through each position i from 1 to n.
- For every i, try all possible partition sizes from 1 to k that end at index i - 1.
- While expanding the partition backwards, maintain the maximum element (curmax) in the current partition.
- The contribution of the current partition is: curmax × partition_length
- Combine this contribution with the best answer before the partition: dp[i - partition_length]
- Store the maximum value among all valid partition choices in dp[i].
- The final answer is dp[n].
#include<iostream>
#include <vector>
using namespace std;
int maxPartitionSum(vector<int>& arr, int k) {
int n = arr.size();
// dp[i] = maximum sum that can be obtained
// using the first i elements of the array
vector<int> dp(n + 1, 0);
for (int i = 1; i <= n; i++) {
int curmax = 0;
int best = 0;
// Try all possible partition lengths ending at index (i - 1)
// with size from 1 to k
for (int j = 1; j <= k && i - j >= 0; j++) {
// Maximum element in the current partition
curmax = max(curmax, arr[i - j]);
// Contribution of current partition:
// (partition length) * (maximum element in partition)
best = max(best, dp[i - j] + curmax * j);
}
// Store the best answer for first i elements
dp[i] = best;
}
return dp[n];
}
int main() {
vector<int> arr = {4, 1, 2, 3};
int k = 2;
cout << maxPartitionSum(arr, k);
return 0;
}
public class Main {
static int maxPartitionSum(int[] arr, int k) {
int n = arr.length;
// dp[i] = maximum sum that can be obtained
// using the first i elements of the array
int[] dp = new int[n + 1];
for (int i = 1; i <= n; i++) {
int curmax = 0;
int best = 0;
// Try all possible partition lengths ending at index (i - 1)
// with size from 1 to k
for (int j = 1; j <= k && i - j >= 0; j++) {
// Maximum element in the current partition
curmax = Math.max(curmax, arr[i - j]);
// Contribution of current partition:
// (partition length) * (maximum element in partition)
best = Math.max(best, dp[i - j] + curmax * j);
}
// Store the best answer for first i elements
dp[i] = best;
}
return dp[n];
}
public static void main(String[] args) {
int[] arr = {4, 1, 2, 3};
int k = 2;
System.out.println(maxPartitionSum(arr, k));
}
}
def maxPartitionSum(arr, k):
n = len(arr)
# dp[i] = maximum sum that can be obtained
# using the first i elements of the array
dp = [0] * (n + 1)
for i in range(1, n + 1):
curmax = 0
best = 0
# Try all possible partition lengths ending at index (i - 1)
# with size from 1 to k
j = 1
while j <= k and i - j >= 0:
# Maximum element in the current partition
curmax = max(curmax, arr[i - j])
# Contribution of current partition:
# (partition length) * (maximum element in partition)
best = max(best, dp[i - j] + curmax * j)
j += 1
# Store the best answer for first i elements
dp[i] = best
return dp[n]
if __name__ == "__main__":
arr = [4, 1, 2, 3]
k = 2
print(maxPartitionSum(arr, k))
using System;
class GfG {
static int MaxPartitionSum(int[] arr, int k) {
int n = arr.Length;
// dp[i] = maximum sum that can be obtained
// using the first i elements of the array
int[] dp = new int[n + 1];
for (int i = 1; i <= n; i++) {
int curmax = 0;
int best = 0;
// Try all possible partition lengths ending at index (i - 1)
// with size from 1 to k
for (int j = 1; j <= k && i - j >= 0; j++) {
// Maximum element in the current partition
curmax = Math.Max(curmax, arr[i - j]);
// Contribution of current partition:
// (partition length) * (maximum element in partition)
best = Math.Max(best, dp[i - j] + curmax * j);
}
// Store the best answer for first i elements
dp[i] = best;
}
return dp[n];
}
static void Main() {
int[] arr = {4, 1, 2, 3};
int k = 2;
Console.WriteLine(MaxPartitionSum(arr, k));
}
}
function maxPartitionSum(arr, k) {
const n = arr.length;
// dp[i] = maximum sum that can be obtained
// using the first i elements of the array
const dp = new Array(n + 1).fill(0);
for (let i = 1; i <= n; i++) {
let curmax = 0;
let best = 0;
// Try all possible partition lengths ending at index (i - 1)
// with size from 1 to k
for (let j = 1; j <= k && i - j >= 0; j++) {
// Maximum element in the current partition
curmax = Math.max(curmax, arr[i - j]);
// Contribution of current partition:
// (partition length) * (maximum element in partition)
best = Math.max(best, dp[i - j] + curmax * j);
}
// Store the best answer for first i elements
dp[i] = best;
}
return dp[n];
}
// Driver code
const arr = [4, 1, 2, 3];
const k = 2;
console.log(maxPartitionSum(arr, k));
Output
14