LeetCode 1499 - Max Value of Equation
This guide will focus on the optimal monotonic queue solution, which achieves linear time complexity and is necessary to
Difficulty: 🔴 Hard
Topics: Array, Queue, Sliding Window, Heap (Priority Queue), Monotonic Queue
Solution
This guide will focus on the optimal monotonic queue solution, which achieves linear time complexity and is necessary to handle the input size limit of 10^5.
Problem Understanding
We are given a list of 2D points sorted in strictly increasing order by their x-coordinate. Each point is represented as [xi, yi], and we are also given an integer k.
Our goal is to find the maximum possible value of the following equation:
$$yi + yj + |xi - xj|$$
subject to the condition:
$$|xi - xj| \leq k$$
where i < j.
Since the points are sorted by x and xi < xj, the absolute value simplifies naturally:
$$|xi - xj| = xj - xi$$
because xj is always greater than xi.
This transforms the equation into:
$$yi + yj + xj - xi$$
We can rearrange it as:
$$(yi - xi) + (yj + xj)$$
This transformation is the key observation of the problem.
For every point j, we want to find a valid earlier point i such that:
$$xj - xi \leq k$$
and among all such valid points, we want the largest possible value of:
$$yi - xi$$
because (yj + xj) is fixed for the current point j.
The constraints are especially important here:
points.lengthcan be as large as100,000- Coordinates can be large, up to
10^8 - Points are already sorted by x-coordinate
A quadratic solution checking every pair would require up to:
$$O(n^2) = 10^{10}$$
operations in the worst case, which is far too slow.
The problem guarantees that at least one valid pair exists, so we never need to worry about returning an invalid result.
Important edge cases include situations where only adjacent points satisfy the distance condition, negative y values that affect equation scoring, and large windows where many candidate points remain valid. We must also carefully remove expired points whose x-distance exceeds k.
Approaches
Brute Force
The most direct approach is to examine every possible pair (i, j) where i < j.
For each pair, we compute:
$$yi + yj + |xi - xj|$$
and check whether:
$$|xi - xj| \leq k$$
If the pair is valid, we update the maximum answer.
This approach is guaranteed to be correct because it evaluates every possible valid pair. However, since there are O(n²) pairs, it becomes infeasible for n = 100,000.
Optimal Approach, Monotonic Queue
The key mathematical observation is:
$$yi + yj + |xi - xj|$$
becomes:
$$(yi - xi) + (yj + xj)$$
For a fixed point j, the value (yj + xj) is constant.
Therefore, we only need to find the largest:
$$yi - xi$$
among all valid previous points satisfying:
$$xj - xi \leq k$$
This naturally suggests maintaining candidate points in a data structure.
We use a deque (double-ended queue) to maintain candidate points in decreasing order of:
$$yi - xi$$
The deque serves two purposes:
- It removes expired points that no longer satisfy the distance constraint.
- It keeps only the best candidates for maximizing the equation.
By maintaining monotonic order, the best candidate is always at the front of the deque.
Since each point enters and leaves the deque at most once, the total runtime becomes linear.
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(n²) | O(1) | Checks every valid pair |
| Optimal | O(n) | O(n) | Uses a monotonic deque to maintain best candidates |
Algorithm Walkthrough
- Initialize a deque and a variable
best_answer.
The deque will store candidate points as tuples:
(x, y - x)
We maintain the deque in decreasing order of (y - x).
2. Iterate through each point (x, y) in points.
This point acts as the current j.
3. Remove expired points from the front of the deque.
If:
$$x - old_x > k$$
then that point can no longer form a valid pair with the current point or any future point because x-values only increase. 4. Compute the candidate equation value.
If the deque is not empty, the front contains the largest available:
$$yi - xi$$
So we calculate:
$$(x + y) + deque[0]$$
and update the maximum answer. 5. Maintain monotonic order.
Before adding the current point, remove elements from the back while:
$$current(y - x) \geq deque[-1]$$
Such points are never useful again because the current point has an equal or better score and a larger x-value. 6. Insert the current point into the deque.
Store:
(x, y - x)
7. Continue until all points are processed.
Why it works
The deque always maintains valid candidate points sorted in decreasing order of (yi - xi). The front therefore always contains the best possible previous point for maximizing the equation at the current position. Since expired points are removed immediately and dominated candidates are discarded, every point is considered exactly once while preserving correctness.
Python Solution
from collections import deque
from typing import List
class Solution:
def findMaxValueOfEquation(self, points: List[List[int]], k: int) -> int:
candidate_points = deque()
best_answer = float("-inf")
for x, y in points:
# Remove points outside distance k
while candidate_points and x - candidate_points[0][0] > k:
candidate_points.popleft()
# Compute equation value
if candidate_points:
best_answer = max(
best_answer,
x + y + candidate_points[0][1]
)
current_value = y - x
# Maintain decreasing order of (y - x)
while candidate_points and candidate_points[-1][1] <= current_value:
candidate_points.pop()
candidate_points.append((x, current_value))
return best_answer
The implementation follows the algorithm directly.
We first create a deque to store candidate points. Each entry contains the x-coordinate and the transformed value (y - x).
For every point, we first remove expired candidates from the front. Since points are sorted by x-coordinate, once a point becomes invalid, it can never become valid again.
After pruning invalid points, we use the front of the deque to compute the equation. Because the deque is maintained in decreasing order of (y - x), the front always represents the best possible candidate.
Before inserting the current point, we remove weaker candidates from the back. If the current point has a larger or equal (y - x), any smaller value becomes permanently dominated and never useful again.
Finally, we append the current point and continue.
Go Solution
func findMaxValueOfEquation(points [][]int, k int) int {
type pair struct {
x int
value int // y - x
}
deque := make([]pair, 0)
bestAnswer := -(1 << 60)
for _, point := range points {
x, y := point[0], point[1]
// Remove expired points
for len(deque) > 0 && x-deque[0].x > k {
deque = deque[1:]
}
// Compute equation value
if len(deque) > 0 {
candidate := x + y + deque[0].value
if candidate > bestAnswer {
bestAnswer = candidate
}
}
currentValue := y - x
// Maintain decreasing order
for len(deque) > 0 &&
deque[len(deque)-1].value <= currentValue {
deque = deque[:len(deque)-1]
}
deque = append(deque, pair{
x: x,
value: currentValue,
})
}
return bestAnswer
}
The Go implementation mirrors the Python solution closely. Since Go does not provide a built-in deque, we simulate one using a slice.
Removing from the front is done using slicing:
deque = deque[1:]
The integer range in Go is sufficient for this problem because the maximum possible result remains within 32-bit bounds, but using a very negative initialization value like -(1 << 60) ensures correctness without overflow concerns.
Worked Examples
Example 1
Input:
points = [[1,3],[2,0],[5,10],[6,-10]]
k = 1
We track:
- deque =
(x, y - x) - answer = maximum equation value
| Step | Point (x,y) |
Deque Before | Valid Best | Equation Value | Deque After | Answer |
|---|---|---|---|---|---|---|
| 1 | (1,3) | [] | none | none | [(1,2)] | -∞ |
| 2 | (2,0) | [(1,2)] | (1,2) | 2 + 0 + 2 = 4 | [(1,2),(2,-2)] | 4 |
| 3 | (5,10) | [(1,2),(2,-2)] | none, expired | none | [(5,5)] | 4 |
| 4 | (6,-10) | [(5,5)] | (5,5) | 6 - 10 + 5 = 1 | [(5,5),(6,-16)] | 4 |
Final answer:
4
Example 2
Input:
points = [[0,0],[3,0],[9,2]]
k = 3
| Step | Point (x,y) |
Deque Before | Valid Best | Equation Value | Deque After | Answer |
|---|---|---|---|---|---|---|
| 1 | (0,0) | [] | none | none | [(0,0)] | -∞ |
| 2 | (3,0) | [(0,0)] | (0,0) | 3 + 0 + 0 = 3 | [(3,-3)] | 3 |
| 3 | (9,2) | [(3,-3)] | none, expired | none | [(9,-7)] | 3 |
Final answer:
3
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n) | Each point enters and leaves the deque at most once |
| Space | O(n) | The deque may store up to n candidate points |
The algorithm is linear because every point is appended to the deque exactly once and removed at most once. Although there are nested while loops, the total number of removals across the entire execution is bounded by n, making the amortized runtime O(n).
Test Cases
class Solution:
def findMaxValueOfEquation(self, points, k):
from collections import deque
dq = deque()
ans = float("-inf")
for x, y in points:
while dq and x - dq[0][0] > k:
dq.popleft()
if dq:
ans = max(ans, x + y + dq[0][1])
curr = y - x
while dq and dq[-1][1] <= curr:
dq.pop()
dq.append((x, curr))
return ans
sol = Solution()
assert sol.findMaxValueOfEquation(
[[1,3],[2,0],[5,10],[6,-10]], 1
) == 4 # Example 1
assert sol.findMaxValueOfEquation(
[[0,0],[3,0],[9,2]], 3
) == 3 # Example 2
assert sol.findMaxValueOfEquation(
[[1,1],[2,2]], 10
) == 4 # Minimum valid input size
assert sol.findMaxValueOfEquation(
[[1,-5],[2,-2],[3,-1]], 2
) == -1 # Negative y-values
assert sol.findMaxValueOfEquation(
[[1,10],[100,20]], 99
) == 129 # Large x difference still valid
assert sol.findMaxValueOfEquation(
[[1,5],[2,3],[3,100],[4,2]], 3
) == 106 # Better later point dominates earlier
assert sol.findMaxValueOfEquation(
[[0,0],[1,0],[2,0],[3,0]], 1
) == 1 # Only adjacent points valid
assert sol.findMaxValueOfEquation(
[[1,2],[2,4],[3,6],[4,8]], 10
) == 13 # Increasing values
assert sol.findMaxValueOfEquation(
[[-10,5],[0,10],[5,-5]], 20
) == 25 # Negative x-values
| Test | Why |
|---|---|
| Example 1 | Validates provided example |
| Example 2 | Validates second example |
| Two points only | Minimum input size |
| Negative y-values | Ensures negative scoring works |
| Large x difference | Verifies k boundary handling |
| Dominating candidate | Tests monotonic deque removal |
| Adjacent only valid | Verifies expiration logic |
| Increasing sequence | Tests larger optimal pair |
| Negative x-values | Ensures coordinate signs are handled correctly |
Edge Cases
Only One Valid Pair Exists
Sometimes only a single pair satisfies the distance constraint. A naive implementation might accidentally miss it due to improper window maintenance. Since the deque removes expired points only when x - old_x > k, the implementation preserves all valid candidates and guarantees the lone valid pair is evaluated.
Negative Values in Coordinates
The equation may produce negative results when y values are negative. An incorrect implementation might initialize the answer to 0, which would fail in such situations. This solution initializes the answer to negative infinity, ensuring even entirely negative outcomes are handled correctly.
Large Valid Windows
When k is very large, many points remain valid simultaneously. Without pruning dominated candidates, performance could degrade significantly. The monotonic deque removes weaker candidates immediately, ensuring only potentially optimal points remain and preserving linear complexity.
Expired Candidates at the Front
A subtle bug occurs if expired points are not removed before computing the equation. This could incorrectly use an invalid point whose x-distance exceeds k. The implementation explicitly removes expired points first, guaranteeing every computed equation satisfies the constraint.