Even Odd Sum Equilibrium — Problem Statement & Solution Guide
Quick Answer & Algorithm Key Takeaway
Master coding challenges related to Arrays and solve the Even Odd Sum Equilibrium problem optimally.
O(n)O(n)Problem Description
Given an integer array values, you may delete any number of elements (possibly none) while preserving the original order, thereby forming a subsequence. Index the subsequence from 0. Let E be the sum of elements at even positions of the subsequence and O be the sum of elements at odd positions. Your task is to obtain the largest possible value of E such that E = O. If no subsequence satisfies the equality, output 0. The algorithm must run in linear time relative to the array length.
DSA Pattern Breakdown
DSA Pattern Breakdown
"Even Odd Sum Equilibrium"
WHY DOES IT MATTER?
Balancing two alternating aggregates appears in load‑balancing, financial ledger reconciliation, and signal processing where even‑odd sampling must match. Mastering this DP pattern teaches you to handle constraints that depend on the position parity of chosen items, a recurring theme in combinatorial optimization.
OPTIMIZATION CHALLENGE
The key insight is to treat the alternating‑position constraint as a signed sum (±v) and to store only the best total for each signed‑difference. This collapses an exponential state space into a linear one by exploiting the fact that only the difference matters, not the exact composition of the subsequence.
REAL-WORLD CONNECTION
Think of a streaming service that alternates between high‑resolution and low‑resolution video chunks to meet bandwidth caps. The total high‑resolution data (even slots) must equal low‑resolution data (odd slots) for a smooth experience; the DP decides which chunks to keep to maximize quality while keeping the two sums balanced.
When coding, use two unordered_maps (or vectors with offset) for parity 0 and 1, and update them in a copy‑on‑write fashion each iteration to avoid overwriting states you still need to transition from.
COMPLEXITY AT A GLANCE
O(n)O(n)Core Theory — Why This Approach?
The problem can be reframed as selecting a subsequence and assigning a + sign to elements that land on even indices of the subsequence and a – sign to those on odd indices. Let diff = (sum of even‑position elements) – (sum of odd‑position elements). The goal is to achieve diff = 0 while maximizing the even‑position sum E, which is equivalent to maximizing the total selected sum because total = E+O = 2E when diff = 0. A naïve exhaustive search would try all 2^n subsequences, compute the parity of each element on the fly and keep the best valid one – impossible for n > 30. The optimal paradigm is dynamic programming over the possible diff values, maintaining for each parity (next index even or odd) the maximum total sum achievable for that diff. When we process a new value v we either skip it or take it, which flips the parity and updates diff by +v (if we are currently at an even position) or –v (if at an odd position). By storing only the best total for each (parity, diff) pair in a hash map we prune the exponential search space to linear in n times the number of distinct diffs, which in practice is bounded by the sum of absolute values. This DP yields the maximum E in O(n·U) time where U is the range of reachable diffs, and O(U) space.
Interview Questions on This Problem
Q1How would you modify the solution if the requirement changed from E = O to E ≥ O with the goal of maximizing E?
Treat the diff as E‑O and keep DP states for the maximum E for each diff. At the end, scan all states where diff ≥ 0 and pick the largest stored E. The transition logic stays the same; only the final selection criteria changes.
Q2Explain why a greedy approach that always picks the next larger element for an even position fails on this problem.
Greedy ignores the future impact on the alternating parity. Picking a large element for an even slot may force a small or negative element into the subsequent odd slot, making diff non‑zero and possibly preventing any valid equilibrium, whereas a smaller even choice could allow a later combination that balances diff and yields a higher total E.
Q3In a distributed system, how could you parallelize the DP computation for very large arrays?
Split the array into blocks, compute local DP maps for each block assuming all possible entry parity and diff offsets, then merge the maps by convolving the diff dimensions (similar to prefix‑sum DP merging). The merge step combines left and right block states respecting parity flips, enabling map‑reduce style parallelism.
Examples
Input
[4,1,2,3,5]
Output
6
Explanation: One optimal subsequence is [4,1,2,5]. Even‑indexed elements are 4 (at index 0) and 2 (at index 2), giving E = 4+2 = 6. Odd‑indexed elements are 1 (at index 1) and 5 (at index 3), giving O = 1+5 = 6. No other valid subsequence yields a larger equal sum, so the answer is 6.
Input
[10,-2,8,-4,6]
Output
0
Explanation: All possible subsequences were examined. No subsequence has the sum of even‑position elements equal to the sum of odd‑position elements. Hence the maximum achievable equal sum is 0.
Input
[1,1,1,1,1,1]
Output
3
Explanation: Taking the whole array produces even‑position sum E = 1+1+1 = 3 and odd‑position sum O = 1+1+1 = 3, satisfying the condition. Any shorter subsequence would give a smaller equal sum, so the maximum is 3.
Constraints
- 1 <= values.length <= 100000
- -1000000000 <= values[i] <= 1000000000
- Time complexity O(n)
- Auxiliary space O(1)
Optimal Approach & Strategy
The optimized approach involves using a prefix sum array to calculate the cumulative sums of weights on even and odd compartments, allowing for a more efficient calculation of the maximum allocatable weight with a time complexity of O(n).
Brute Force Approach
A brute-force approach involves trying all possible combinations of items on even and odd compartments and calculating the difference in weights, resulting in a time complexity of O(2^n). This approach is inefficient for large inputs.
Code Solutions
function evenOddSumEquilibrium(values) {
// dpEven and dpOdd map diff -> max sumEven
const dpEven = new Map(); // next index is even
const dpOdd = new Map(); // next index is odd
dpEven.set(0, 0);
for (const v of values) {
const nextEven = new Map(dpEven);
const nextOdd = new Map(dpOdd);
// take v at even position
for (const [diff, sumEven] of dpEven.entries()) {
const newDiff = diff + v;
const newSumEven = sumEven + v;
if (!nextOdd.has(newDiff) || nextOdd.get(newDiff) < newSumEven) {
nextOdd.set(newDiff, newSumEven);
}
}
// take v at odd position
for (const [diff, sumEven] of dpOdd.entries()) {
const newDiff = diff - v;
const newSumEven = sumEven; // unchanged
if (!nextEven.has(newDiff) || nextEven.get(newDiff) < newSumEven) {
nextEven.set(newDiff, newSumEven);
}
}
dpEven.clear();
dpOdd.clear();
for (const [k, v] of nextEven) dpEven.set(k, v);
for (const [k, v] of nextOdd) dpOdd.set(k, v);
}
let ans = 0;
if (dpEven.has(0)) ans = Math.max(ans, dpEven.get(0));
if (dpOdd.has(0)) ans = Math.max(ans, dpOdd.get(0));
return ans;
}
const readline = require('readline');
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
let lines = [];
rl.on('line', line => lines.push(line.trim()));
rl.on('close', () => {
const n = parseInt(lines[0]);
const values = lines[1].split(/\s+/).map(Number);
console.log(evenOddSumEquilibrium(values));
});#include <bits/stdc++.h>
using namespace std;
int evenOddSumEquilibrium(const vector<int>& values) {
// dpEven[diff] = maximum sum of elements placed at even positions so far
// when the next element to be placed will be at an even index.
// dpOdd[diff] = same, but the next index is odd.
unordered_map<long long, long long> dpEven, dpOdd;
dpEven[0] = 0; // empty subsequence, next position is even, diff = 0
for (int v : values) {
unordered_map<long long, long long> nextEven = dpEven;
unordered_map<long long, long long> nextOdd = dpOdd;
// Take v when next position is even -> it becomes an even-indexed element
for (auto &p : dpEven) {
long long diff = p.first;
long long sumEven = p.second;
long long newDiff = diff + v; // E - O increases by v
long long newSumEven = sumEven + v; // v contributes to even sum
auto it = nextOdd.find(newDiff);
if (it == nextOdd.end() || it->second < newSumEven) {
nextOdd[newDiff] = newSumEven;
}
}
// Take v when next position is odd -> it becomes an odd-indexed element
for (auto &p : dpOdd) {
long long diff = p.first;
long long sumEven = p.second; // unchanged, v goes to odd side
long long newDiff = diff - v; // E - O decreases by v
auto it = nextEven.find(newDiff);
if (it == nextEven.end() || it->second < sumEven) {
nextEven[newDiff] = sumEven;
}
}
dpEven.swap(nextEven);
dpOdd.swap(nextOdd);
}
long long ans = 0; // empty subsequence gives E = 0
if (dpEven.count(0)) ans = max(ans, dpEven[0]);
if (dpOdd.count(0)) ans = max(ans, dpOdd[0]);
return static_cast<int>(ans);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n; if(!(cin >> n)) return 0;
vector<int> values(n);
for (int i = 0; i < n; ++i) cin >> values[i];
cout << evenOddSumEquilibrium(values) << "\n";
return 0;
}import java.util.*;
public class Main {
// Returns the maximum possible sum E such that a subsequence exists where
// the sum of elements at even positions equals the sum at odd positions (E = O).
public static int evenOddSumEquilibrium(int[] values) {
Map<Long, Long> dpEven = new HashMap<>(); // diff -> max sumEven, next index even
Map<Long, Long> dpOdd = new HashMap<>(); // diff -> max sumEven, next index odd
dpEven.put(0L, 0L);
for (int v : values) {
Map<Long, Long> nextEven = new HashMap<>(dpEven);
Map<Long, Long> nextOdd = new HashMap<>(dpOdd);
// place v at even position
for (Map.Entry<Long, Long> e : dpEven.entrySet()) {
long diff = e.getKey();
long sumEven = e.getValue();
long newDiff = diff + v;
long newSumEven = sumEven + v;
nextOdd.merge(newDiff, newSumEven, Math::max);
}
// place v at odd position
for (Map.Entry<Long, Long> e : dpOdd.entrySet()) {
long diff = e.getKey();
long sumEven = e.getValue(); // unchanged
long newDiff = diff - v;
nextEven.merge(newDiff, sumEven, Math::max);
}
dpEven = nextEven;
dpOdd = nextOdd;
}
long ans = 0;
if (dpEven.containsKey(0L)) ans = Math.max(ans, dpEven.get(0L));
if (dpOdd.containsKey(0L)) ans = Math.max(ans, dpOdd.get(0L));
return (int) ans;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] values = new int[n];
for (int i = 0; i < n; ++i) values[i] = sc.nextInt();
System.out.println(evenOddSumEquilibrium(values));
}
}def even_odd_sum_equilibrium(values):
"""Return the maximum possible sum E such that a subsequence exists where
the sum of elements at even positions equals the sum at odd positions (E = O)."""
dp_even = {0: 0} # diff -> max sum_even, next index is even
dp_odd = {} # diff -> max sum_even, next index is odd
for v in values:
next_even = dp_even.copy()
next_odd = dp_odd.copy()
# place v at an even position
for diff, sum_even in dp_even.items():
new_diff = diff + v
new_sum_even = sum_even + v
if new_diff not in next_odd or next_odd[new_diff] < new_sum_even:
next_odd[new_diff] = new_sum_even
# place v at an odd position
for diff, sum_even in dp_odd.items():
new_diff = diff - v
if new_diff not in next_even or next_even[new_diff] < sum_even:
next_even[new_diff] = sum_even
dp_even, dp_odd = next_even, next_odd
ans = 0
if 0 in dp_even:
ans = max(ans, dp_even[0])
if 0 in dp_odd:
ans = max(ans, dp_odd[0])
return ans
if __name__ == "__main__":
n = int(input())
values = list(map(int, input().split()))
print(even_odd_sum_equilibrium(values))function evenOddSumEquilibrium(values) {
// dpEven and dpOdd map diff -> max sumEven
const dpEven = new Map(); // next index is even
const dpOdd = new Map(); // next index is odd
dpEven.set(0, 0);
for (const v of values) {
const nextEven = new Map(dpEven);
const nextOdd = new Map(dpOdd);
// take v at even position
for (const [diff, sumEven] of dpEven.entries()) {
const newDiff = diff + v;
const newSumEven = sumEven + v;
if (!nextOdd.has(newDiff) || nextOdd.get(newDiff) < newSumEven) {
nextOdd.set(newDiff, newSumEven);
}
}
// take v at odd position
for (const [diff, sumEven] of dpOdd.entries()) {
const newDiff = diff - v;
const newSumEven = sumEven; // unchanged
if (!nextEven.has(newDiff) || nextEven.get(newDiff) < newSumEven) {
nextEven.set(newDiff, newSumEven);
}
}
dpEven.clear();
dpOdd.clear();
for (const [k, v] of nextEven) dpEven.set(k, v);
for (const [k, v] of nextOdd) dpOdd.set(k, v);
}
let ans = 0;
if (dpEven.has(0)) ans = Math.max(ans, dpEven.get(0));
if (dpOdd.has(0)) ans = Math.max(ans, dpOdd.get(0));
return ans;
}
const readline = require('readline');
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
let lines = [];
rl.on('line', line => lines.push(line.trim()));
rl.on('close', () => {
const n = parseInt(lines[0]);
const values = lines[1].split(/\s+/).map(Number);
console.log(evenOddSumEquilibrium(values));
});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.