Optimal Stack Horizon — Problem Statement & Solution Guide
Problem Description
Given an array of integers, find the optimal stack horizon by sorting the array in descending order and using two pointers to find the maximum sum of elements that can be obtained by moving the two pointers towards each other.
DSA Pattern Breakdown
DSA Pattern Breakdown
"Optimal Stack Horizon"
WHY DOES IT MATTER?
The sort‑then‑two‑pointer pattern is a cornerstone for problems that require optimal pair selection under monotonic constraints. It reduces quadratic search spaces to linear scans, making it indispensable for performance‑critical code in interviews and production.
OPTIMIZATION CHALLENGE
The key insight is that sorting imposes a total order, allowing the algorithm to discard any pair that cannot beat the current best because moving inward can only lower the sum. This eliminates the need for nested loops.
REAL-WORLD CONNECTION
Think of a warehouse loading dock where the heaviest crates (largest values) are placed at the front and the lightest at the back. A forklift (two pointers) picks one crate from each end to maximize load without re‑ordering the entire inventory, mirroring how the algorithm efficiently balances extremes.
During an interview, sort first, then write the two‑pointer loop as a separate function. Keep the loop simple: compute sum, update max, then move the left pointer rightward if it can still increase the sum, otherwise move the right pointer leftward. This clarity often earns extra points.
COMPLEXITY AT A GLANCE
O(N log N)O(1)Core Theory — Why This Approach?
The "Optimal Stack Horizon" problem is a classic example of leveraging order statistics to reduce combinatorial explosion. A naive solution would examine every possible pair of elements, leading to O(N²) time, which quickly becomes infeasible for N in the order of 10⁵ or more. By first sorting the array in descending order, we impose a monotonic structure that enables a two‑pointer sweep: one pointer starts at the largest element, the other at the smallest. Because the array is sorted, moving either pointer inward can only decrease the potential sum, allowing us to prune the search space dramatically. This paradigm—sorting followed by a linear two‑pointer scan—transforms a quadratic problem into O(N log N) time while using only O(1) extra space, which is the optimal trade‑off for this class of pair‑selection problems.
The optimal approach hinges on the insight that the maximum sum of any two elements must involve the largest values. After sorting, the two‑pointer technique systematically evaluates candidate pairs without revisiting combinations, guaranteeing that the global maximum is found. This method also gracefully handles duplicate values and negative numbers, as the sorted order preserves relative magnitudes. In contrast, brute‑force enumeration suffers from redundant calculations and cache inefficiency, making it unsuitable for large‑scale inputs common in production systems.
Interview Questions on This Problem
Q1How would you modify the two‑pointer solution if the problem asked for the maximum product of two elements instead of the sum?
Sort the array in descending order. Since the product of two large positive numbers is maximal, the candidate pairs are the two largest positives. However, if negatives are present, the product of the two most negative numbers could be larger. After sorting, compare the product of the first two elements with the product of the last two (most negative) elements and return the larger.
Q2Can you solve the problem in O(N) time without sorting? Explain the trade‑offs.
Yes, by scanning the array once to track the two largest values (max1 and max2). The maximum sum is max1 + max2. This achieves O(N) time and O(1) space but loses the flexibility of the two‑pointer pattern for extensions (e.g., constraints on index distance) and does not handle scenarios where additional ordering information is required.
Q3In a distributed system where the array is sharded across multiple nodes, how would you compute the optimal stack horizon efficiently?
Each node locally computes its two largest elements. A central coordinator then gathers these local candidates (at most two per node) and performs a final two‑pointer or simple max‑pair computation on the aggregated list, which is O(K log K) where K is the number of shards, typically far smaller than the total N.
Examples
Input
[3, 2, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
Output
17
Explanation: Step-by-step: Given the array [3, 2, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20], we first sort the array in descending order. Then, we use two pointers, one at the start and one at the end of the array, to find the optimal stack horizon. The optimal stack horizon is the maximum sum of elements that can be obtained by moving the two pointers towards each other. In this case, the optimal stack horizon is 17, which is the sum of the two largest numbers in the array.
Input
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
Output
12
Explanation: Step-by-step: Given the array [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20], we first sort the array in descending order. Then, we use two pointers, one at the start and one at the end of the array, to find the optimal stack horizon. The optimal stack horizon is the maximum sum of elements that can be obtained by moving the two pointers towards each other. In this case, the optimal stack horizon is 12, which is the sum of the two middle numbers in the array.
Constraints
- 1 <= N <= 10^5
- -10^9 <= arr[i] <= 10^9
- Time Complexity expected: O(N) or O(N log N)
- Space Complexity expected: O(1) or O(N)
Optimal Approach & Strategy
Sort the array descending (O(N log N)) and then sweep with two pointers from opposite ends, updating the maximum sum in O(N) time.
Brute Force Approach
Check every possible pair of elements and keep the largest sum, which requires O(N²) time.
Verified Code Solutions
function solution(nums) {
nums.sort((a, b) => b - a);
let left = 0;
let right = nums.length - 1;
let maxSum = 0;
while (left < right) {
maxSum = Math.max(maxSum, nums[left] + nums[right]);
if (nums[left] === nums[right]) {
left++;
right--;
} else if (nums[left] < nums[right]) {
left++;
} else {
right--;
}
}
return maxSum;
}class Solution {
public:
int solution(vector<int>& nums) {
sort(nums.begin(), nums.end(), greater<int>());
int left = 0;
int right = nums.size() - 1;
int max_sum = 0;
while (left < right) {
max_sum = max(max_sum, nums[left] + nums[right]);
if (nums[left] == nums[right]) {
left++;
right--;
} else if (nums[left] < nums[right]) {
left++;
} else {
right--;
}
}
return max_sum;
}
};class Solution {
public int solution(int[] nums) {
Arrays.sort(nums);
int left = 0;
int right = nums.length - 1;
int maxSum = 0;
while (left < right) {
maxSum = Math.max(maxSum, nums[left] + nums[right]);
if (nums[left] == nums[right]) {
left++;
right--;
} else if (nums[left] < nums[right]) {
left++;
} else {
right--;
}
}
return maxSum;
}
}def solution(nums):
nums.sort(reverse=True)
left = 0
right = len(nums) - 1
max_sum = 0
while left < right:
max_sum = max(max_sum, nums[left] + nums[right])
if nums[left] == nums[right]:
left += 1
right -= 1
elif nums[left] < nums[right]:
left += 1
else:
right -= 1
return max_sumfunction solution(nums) {
nums.sort((a, b) => b - a);
let left = 0;
let right = nums.length - 1;
let maxSum = 0;
while (left < right) {
maxSum = Math.max(maxSum, nums[left] + nums[right]);
if (nums[left] === nums[right]) {
left++;
right--;
} else if (nums[left] < nums[right]) {
left++;
} else {
right--;
}
}
return maxSum;
}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.