Optimal Array Partition — Problem Statement & Solution Guide
Quick Answer & Algorithm Key Takeaway
Master coding challenges related to Two Pointers and solve the Optimal Array Partition problem optimally.
O(n)O(1)Problem Description
Given an integer array weights of length n, choose an index i (1 ≤ i < n) that splits the array into a left part weights[0..i‑1] and a right part weights[i..n‑1]. The goal is to make the absolute difference between the sum of the left part and the sum of the right part as small as possible. Return the index i that yields this minimum difference. If multiple indices produce the same smallest difference, return the smallest such i. The algorithm must run in linear time and use only constant extra space.
DSA Pattern Breakdown
DSA Pattern Breakdown
"Optimal Array Partition"
WHY DOES IT MATTER?
Balancing two partitions with minimal difference appears in load‑balancing, financial settlement, and memory allocation; mastering this pattern teaches you to turn a quadratic comparison into a linear scan by exploiting cumulative information.
OPTIMIZATION CHALLENGE
The key insight is that the right sum is not independent—it is simply total‑left. By maintaining only the left sum during a single traversal, you eliminate the need for nested loops or extra arrays.
REAL-WORLD CONNECTION
Think of a conveyor belt where items are loaded onto two trucks; you continuously track the weight on the first truck (left sum) while the remaining weight automatically belongs to the second truck (right sum), adjusting the split point on the fly.
During an interview, compute the total sum first, then iterate once updating leftSum; compare |total‑2*leftSum| to the best diff—this one‑line expression often impresses interviewers.
COMPLEXITY AT A GLANCE
O(n)O(1)Core Theory — Why This Approach?
The problem asks for an index that balances the sum of two sub‑arrays. A naïve solution would recompute the left and right sums for every possible split, leading to O(n²) time, which quickly becomes infeasible for n up to 10⁵ or more. The optimal paradigm leverages prefix sums: by scanning the array once while maintaining a running left sum, the right sum can be derived as total‑left, allowing the absolute difference to be evaluated in constant time per index. This single‑pass, two‑pointer‑like technique reduces the overall complexity to linear time, which is the hallmark of efficient array‑partition problems.
Interview Questions on This Problem
Q1How would you modify the solution if the array could contain negative numbers?
The same linear‑scan works because the total sum accounts for negatives; you still compute left and right sums on the fly and track the minimal absolute difference.
Q2Can you extend the algorithm to return all indices that achieve the minimal difference?
Yes—during the single pass keep a list of indices whenever a new minimal difference is found, and if the current difference equals the known minimum, append the index to the list.
Q3What is the time‑space trade‑off if you pre‑compute a prefix‑sum array instead of using a running variable?
Pre‑computing a prefix‑sum array also gives O(n) time for queries, but it uses O(n) extra space; the running‑variable version achieves the same O(n) time with O(1) additional space.
Examples
Input
5 3 1 2 4 3
Output
3
Explanation: Total sum = 13. Prefix sums: [3,4,6,10,13]. For i=1: left=3, right=10, diff=7. For i=2: left=4, right=9, diff=5. For i=3: left=6, right=7, diff=1 (minimum). For i=4: left=10, right=3, diff=7. The smallest diff is 1 at i=3, so output 3.
Input
6 10 -5 3 -2 8 -1
Output
4
Explanation: Total sum = 13. Prefix sums: [10,5,8,6,14,13]. Compute diffs: i=1 → |10‑3|=7 i=2 → |5‑8|=3 i=3 → |8‑5|=3 i=4 → |6‑7|=1 (minimum) i=5 → |14‑(-1)|=15 Minimum difference is 1 at i=4, so output 4.
Input
6 1 2 3 4 5 6
Output
4
Explanation: Total sum = 21. Prefix sums: [1,3,6,10,15,21]. diffs: i=1 → |1‑20|=19 i=2 → |3‑18|=15 i=3 → |6‑15|=9 i=4 → |10‑11|=1 (minimum) i=5 → |15‑6|=9 Smallest diff is 1 at i=4, thus output 4.
Constraints
- 1 ≤ weights.length ≤ 2·10⁵
- -10⁹ ≤ weights[i] ≤ 10⁹
- All calculations fit in 64‑bit signed integer
Optimal Approach & Strategy
First compute the total sum, then iterate once maintaining a running left sum; the right sum is total‑left, so the difference can be evaluated in O(1) per index, yielding O(n) time and O(1) extra space.
Brute Force Approach
For each possible split index, sum the left part and the right part separately and compute their absolute difference; keep the index with the smallest difference.
Code Solutions
/**
* @param {number[]} weights - The input array of integers
* @return {number} - The index i (1 <= i < n) that minimizes the absolute difference between the sum of weights[0..i-1] and weights[i..n-1].
* If multiple indices yield the same minimum difference, return the smallest such index.
*/
function optimalPartition(weights) {
const n = weights.length;
if (n < 2) return 0;
let totalSum = 0;
for (let w of weights) {
totalSum += w;
}
let leftSum = 0;
let minDiff = Infinity;
let bestIndex = 1;
for (let i = 1; i < n; i++) {
leftSum += weights[i - 1];
const rightSum = totalSum - leftSum;
const diff = Math.abs(leftSum - rightSum);
if (diff < minDiff) {
minDiff = diff;
bestIndex = i;
}
}
return bestIndex;
}
// Driver code
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
terminal: false
});
let lines = [];
rl.on('line', (line) => {
lines.push(line);
});
rl.on('close', () => {
const n = parseInt(lines[0]);
const weights = lines[1].split(' ').map(Number);
console.log(optimalPartition(weights));
});#include <iostream>
#include <vector>
#include <cmath>
#include <climits>
using namespace std;
int optimalPartition(vector<int>& weights) {
int n = weights.size();
if (n < 2) return 0; // Edge case, though problem states 1 <= i < n
long long totalSum = 0;
for (int w : weights) {
totalSum += w;
}
long long leftSum = 0;
long long minDiff = LLONG_MAX;
int bestIndex = 1;
for (int i = 1; i < n; i++) {
leftSum += weights[i - 1];
long long rightSum = totalSum - leftSum;
long long diff = abs(leftSum - rightSum);
if (diff < minDiff) {
minDiff = diff;
bestIndex = i;
}
}
return bestIndex;
}
int main() {
int n;
cin >> n;
vector<int> weights(n);
for (int i = 0; i < n; i++) {
cin >> weights[i];
}
cout << optimalPartition(weights) << endl;
return 0;
}import java.util.*;
import java.io.*;
public class Main {
/**
* @param weights The input array of integers
* @return The index i (1 <= i < n) that minimizes the absolute difference between the sum of weights[0..i-1] and weights[i..n-1].
* If multiple indices yield the same minimum difference, return the smallest such index.
*/
public static int optimalPartition(int[] weights) {
int n = weights.length;
if (n < 2) return 0;
long totalSum = 0;
for (int w : weights) {
totalSum += w;
}
long leftSum = 0;
long minDiff = Long.MAX_VALUE;
int bestIndex = 1;
for (int i = 1; i < n; i++) {
leftSum += weights[i - 1];
long rightSum = totalSum - leftSum;
long diff = Math.abs(leftSum - rightSum);
if (diff < minDiff) {
minDiff = diff;
bestIndex = i;
}
}
return bestIndex;
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine().trim());
String[] parts = br.readLine().trim().split("\\s+");
int[] weights = new int[n];
for (int i = 0; i < n; i++) {
weights[i] = Integer.parseInt(parts[i]);
}
System.out.println(optimalPartition(weights));
}
}def optimal_partition(weights):
"""
Args:
weights (list[int]): The input array of integers
Returns:
int: The index i (1 <= i < n) that minimizes the absolute difference between the sum of weights[0..i-1] and weights[i..n-1].
If multiple indices yield the same minimum difference, return the smallest such index.
"""
n = len(weights)
if n < 2:
return 0
total_sum = sum(weights)
left_sum = 0
min_diff = float('inf')
best_index = 1
for i in range(1, n):
left_sum += weights[i - 1]
right_sum = total_sum - left_sum
diff = abs(left_sum - right_sum)
if diff < min_diff:
min_diff = diff
best_index = i
return best_index
if __name__ == "__main__":
import sys
input = sys.stdin.read
data = input().split()
n = int(data[0])
weights = list(map(int, data[1:n+1]))
print(optimal_partition(weights))/**
* @param {number[]} weights - The input array of integers
* @return {number} - The index i (1 <= i < n) that minimizes the absolute difference between the sum of weights[0..i-1] and weights[i..n-1].
* If multiple indices yield the same minimum difference, return the smallest such index.
*/
function optimalPartition(weights) {
const n = weights.length;
if (n < 2) return 0;
let totalSum = 0;
for (let w of weights) {
totalSum += w;
}
let leftSum = 0;
let minDiff = Infinity;
let bestIndex = 1;
for (let i = 1; i < n; i++) {
leftSum += weights[i - 1];
const rightSum = totalSum - leftSum;
const diff = Math.abs(leftSum - rightSum);
if (diff < minDiff) {
minDiff = diff;
bestIndex = i;
}
}
return bestIndex;
}
// Driver code
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
terminal: false
});
let lines = [];
rl.on('line', (line) => {
lines.push(line);
});
rl.on('close', () => {
const n = parseInt(lines[0]);
const weights = lines[1].split(' ').map(Number);
console.log(optimalPartition(weights));
});Asked in Top Tech Interviews
Solve in Interative Editor
Ready to test your code? Open our built-in compiler, run custom test suites, and see detailed complexity analysis reports instantly.