1499. Max Value of Equation
Problem Description
You have an array of points on a 2D plane where each point is represented as [x, y]
coordinates. The points are sorted by their x-values in ascending order, meaning x₁ < x₂ < x₃ < ... < xₙ
.
Given these points and an integer k
, you need to find the maximum value of the equation:
yᵢ + yⱼ + |xᵢ - xⱼ|
The constraints are:
- You must choose two different points
i
andj
wherei < j
- The x-distance between the two points must not exceed
k
:|xᵢ - xⱼ| ≤ k
- The problem guarantees at least one valid pair exists
Since the points are sorted by x-values and i < j
, we know xⱼ > xᵢ
, so |xᵢ - xⱼ| = xⱼ - xᵢ
. This simplifies our equation to:
yᵢ + yⱼ + (xⱼ - xᵢ) = (yᵢ - xᵢ) + (xⱼ + yⱼ)
The solution uses a priority queue (min-heap) to efficiently track potential point pairs. For each point (x, y)
:
- Remove points from the heap where the x-distance exceeds
k
- If valid points remain, calculate the maximum value using the current point and the best previous point
- Add the current point to the heap with key
(x - y)
for future comparisons
The heap stores tuples of (x - y, x)
where the first element serves as the priority key. By maintaining the minimum x - y
value at the top of the heap, we can maximize the equation value when combined with future points.
Intuition
The key insight comes from rewriting the equation. Since points are sorted by x-values and we need i < j
, we know xⱼ > xᵢ
, which means |xᵢ - xⱼ| = xⱼ - xᵢ
.
So our equation becomes:
yᵢ + yⱼ + (xⱼ - xᵢ) = (yⱼ + xⱼ) + (yᵢ - xᵢ)
This transformation is crucial! Now we can think of each point as having two components:
- When point
j
is the second point: contribute(yⱼ + xⱼ)
- When point
i
is the first point: contribute(yᵢ - xᵢ)
As we iterate through points from left to right, for each current point j
, we want to find the best previous point i
that:
- Is within distance
k
:xⱼ - xᵢ ≤ k
- Maximizes
(yᵢ - xᵢ)
This naturally suggests maintaining a collection of previous points, but we need to handle two operations efficiently:
- Remove points that are now too far away (outside the
k
distance) - Find the point with maximum
(yᵢ - xᵢ)
value
A min-heap works perfectly here! We store (xᵢ - yᵢ, xᵢ)
in the heap (negating to get maximum). The heap automatically keeps the best candidate at the top. As we process each new point, we:
- Clean out points beyond distance
k
- Use the heap's top element (if any) to calculate a potential maximum
- Add the current point for future use
This sliding window approach with a heap ensures we always consider the best valid pairing while maintaining efficiency.
Learn more about Queue, Sliding Window, Monotonic Queue and Heap (Priority Queue) patterns.
Solution Approach
We implement the solution using a min-heap to maintain candidate points efficiently:
Data Structure: A min-heap (priority queue) storing tuples (x - y, x)
where:
- First element
(x - y)
serves as the priority key (smaller values have higher priority) - Second element
x
helps us check the distance constraint
Algorithm Steps:
-
Initialize variables:
ans = -inf
to track the maximum value foundpq = []
as our min-heap
-
Process each point
(x, y)
in order:a. Clean expired points:
while pq and x - pq[0][1] > k: heappop(pq)
Remove points from the heap where the x-distance exceeds
k
. Sincepq[0][1]
contains the x-coordinate of the heap's top element, we check ifx - pq[0][1] > k
.b. Calculate maximum with current point:
if pq: ans = max(ans, x + y - pq[0][0])
If valid points remain, compute the equation value. Since
pq[0][0]
stores(xᵢ - yᵢ)
and we need(yᵢ - xᵢ)
, we use-pq[0][0]
. The complete equation becomes:(y + x) + (-pq[0][0])
= (y + x) + (yᵢ - xᵢ)
= yⱼ + xⱼ + yᵢ - xᵢ
c. Add current point to heap:
heappush(pq, (x - y, x))
Store the current point for future iterations with its
(x - y)
value as the priority key. -
Return the maximum value found across all valid pairs.
The min-heap ensures we always have access to the point with minimum (x - y)
value, which equivalently gives us the maximum (y - x)
value needed to maximize our equation. The sliding window constraint is maintained by removing points beyond distance k
.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the algorithm with points = [[1,3], [2,0], [5,10], [6,-10]] and k = 3.
Initial state:
- ans = -∞
- pq = [] (empty min-heap)
Processing point [1,3]:
- x=1, y=3
- Clean expired: pq is empty, nothing to remove
- Calculate max: pq is empty, skip
- Add to heap: pq = [(1-3, 1)] = [(-2, 1)]
Processing point [2,0]:
- x=2, y=0
- Clean expired: Check if 2 - 1 > 3? No (1 ≤ 3), keep [(-2, 1)]
- Calculate max: ans = max(-∞, 2 + 0 - (-2)) = max(-∞, 4) = 4
- This represents pairing points [1,3] and [2,0]: 3 + 0 + |1-2| = 4
- Add to heap: pq = [(-2, 1), (2, 2)]
Processing point [5,10]:
- x=5, y=10
- Clean expired:
- Check if 5 - 1 > 3? Yes (4 > 3), remove [(-2, 1)]
- Check if 5 - 2 > 3? Yes (3 ≤ 3), keep [(2, 2)]
- Calculate max: ans = max(4, 5 + 10 - 2) = max(4, 13) = 13
- This represents pairing points [2,0] and [5,10]: 0 + 10 + |2-5| = 13
- Add to heap: pq = [(-5, 5), (2, 2)]
Processing point [6,-10]:
- x=6, y=-10
- Clean expired:
- Check if 6 - 5 > 3? No (1 ≤ 3), keep [(-5, 5)]
- Note: (2, 2) would be checked next but (-5, 5) has higher priority
- Calculate max: ans = max(13, 6 + (-10) - (-5)) = max(13, 1) = 13
- This represents pairing points [5,10] and [6,-10]: 10 + (-10) + |5-6| = 1
- Add to heap: pq = [(-5, 5), (2, 2), (16, 6)]
Final answer: 13
The maximum value comes from pairing points [2,0] and [5,10], giving us 0 + 10 + 3 = 13.
Solution Implementation
1from typing import List
2import heapq
3from math import inf
4
5class Solution:
6 def findMaxValueOfEquation(self, points: List[List[int]], k: int) -> int:
7 # Initialize the maximum result as negative infinity
8 max_value = -inf
9
10 # Min-heap to store tuples of (x - y, x)
11 # We want to maximize (y - x) + (current_y + current_x)
12 # Since heapq is a min-heap, we store (x - y) to get the minimum (x - y),
13 # which corresponds to maximum (y - x)
14 min_heap = []
15
16 # Iterate through each point
17 for current_x, current_y in points:
18 # Remove points from heap that are too far away (distance > k)
19 while min_heap and current_x - min_heap[0][1] > k:
20 heapq.heappop(min_heap)
21
22 # If heap is not empty, calculate the value of the equation
23 # with the best previous point
24 if min_heap:
25 # The equation value is: current_x + current_y - (x_i - y_i)
26 # which equals: current_x + current_y + y_i - x_i
27 max_value = max(max_value, current_x + current_y - min_heap[0][0])
28
29 # Add current point to the heap for future comparisons
30 # Store (x - y, x) tuple
31 heapq.heappush(min_heap, (current_x - current_y, current_x))
32
33 return max_value
34
1class Solution {
2 public int findMaxValueOfEquation(int[][] points, int k) {
3 // Initialize the answer to a very small value (negative large number)
4 int maxValue = Integer.MIN_VALUE;
5
6 // Max heap to store pairs of [yi - xi, xi]
7 // Sorted by yi - xi in descending order (max heap based on first element)
8 PriorityQueue<int[]> maxHeap = new PriorityQueue<>((a, b) -> b[0] - a[0]);
9
10 // Iterate through each point
11 for (int[] point : points) {
12 int currentX = point[0];
13 int currentY = point[1];
14
15 // Remove points from heap where distance exceeds k
16 // Since points are sorted by x, currentX >= all previous x values
17 while (!maxHeap.isEmpty() && currentX - maxHeap.peek()[1] > k) {
18 maxHeap.poll();
19 }
20
21 // If there are valid points in the heap, calculate the equation value
22 // Equation: yi + yj + |xi - xj| = (yi - xi) + (yj + xj)
23 // Where current point is j and heap top contains the best i
24 if (!maxHeap.isEmpty()) {
25 int equationValue = currentX + currentY + maxHeap.peek()[0];
26 maxValue = Math.max(maxValue, equationValue);
27 }
28
29 // Add current point to heap for future comparisons
30 // Store [yi - xi, xi] for current point
31 maxHeap.offer(new int[] {currentY - currentX, currentX});
32 }
33
34 return maxValue;
35 }
36}
37
1class Solution {
2public:
3 int findMaxValueOfEquation(vector<vector<int>>& points, int k) {
4 // Initialize the maximum result with a very small value
5 int maxResult = -(1 << 30);
6
7 // Priority queue to store pairs of (yi - xi, xi)
8 // Max heap based on the first element (yi - xi)
9 priority_queue<pair<int, int>> maxHeap;
10
11 // Iterate through each point
12 for (auto& point : points) {
13 int currentX = point[0];
14 int currentY = point[1];
15
16 // Remove points from heap where the x-distance exceeds k
17 // These points are too far from current point to form valid pairs
18 while (!maxHeap.empty() && currentX - maxHeap.top().second > k) {
19 maxHeap.pop();
20 }
21
22 // If there are valid points in the heap, calculate the equation value
23 // Equation: yi + yj + |xi - xj| = (yi - xi) + (xj + yj)
24 // Since xi < xj (points are sorted), |xi - xj| = xj - xi
25 if (!maxHeap.empty()) {
26 // maxHeap.top().first contains (yi - xi) for some previous point i
27 // Current contribution is (xj + yj) where j is the current point
28 maxResult = max(maxResult, currentX + currentY + maxHeap.top().first);
29 }
30
31 // Add current point to the heap for future calculations
32 // Store (y - x) as priority and x as the second value
33 maxHeap.emplace(currentY - currentX, currentX);
34 }
35
36 return maxResult;
37 }
38};
39
1// Global heap operations
2let heapData: Array<[number, number] | null> = [];
3let heapCompare: (a: [number, number], b: [number, number]) => number;
4
5function heapSize(): number {
6 return heapData.length - 1;
7}
8
9function heapSwap(i: number, j: number): void {
10 [heapData[i], heapData[j]] = [heapData[j], heapData[i]];
11}
12
13function heapLt(i: number, j: number): boolean {
14 return heapCompare(heapData[i]!, heapData[j]!) < 0;
15}
16
17function heapify(i: number): void {
18 while (true) {
19 let minIndex = i;
20 const leftChild = i * 2;
21 const rightChild = i * 2 + 1;
22 const heapLength = heapData.length;
23
24 // Check if left child exists and is smaller than current minimum
25 if (leftChild < heapLength && heapLt(leftChild, minIndex)) {
26 minIndex = leftChild;
27 }
28
29 // Check if right child exists and is smaller than current minimum
30 if (rightChild < heapLength && heapLt(rightChild, minIndex)) {
31 minIndex = rightChild;
32 }
33
34 // If minimum changed, swap and continue heapifying
35 if (minIndex !== i) {
36 heapSwap(i, minIndex);
37 i = minIndex;
38 } else {
39 break;
40 }
41 }
42}
43
44function heapPush(value: [number, number]): void {
45 heapData.push(value);
46 let currentIndex = heapSize();
47
48 // Bubble up: swap with parent while current is smaller than parent
49 while (currentIndex >> 1 !== 0 && heapLt(currentIndex, currentIndex >> 1)) {
50 heapSwap(currentIndex, currentIndex >> 1);
51 currentIndex >>= 1;
52 }
53}
54
55function heapPop(): [number, number] {
56 // Swap root with last element
57 heapSwap(1, heapSize());
58 const topElement = heapData.pop();
59
60 // Restore heap property
61 heapify(1);
62 return topElement!;
63}
64
65function heapTop(): [number, number] {
66 return heapData[1]!;
67}
68
69function heapInit(compare: (a: [number, number], b: [number, number]) => number): void {
70 heapData = [null];
71 heapCompare = compare;
72}
73
74/**
75 * Find maximum value of equation yi + yj + |xi - xj| where |xi - xj| <= k
76 * Since points are sorted by x-coordinate and xi < xj, the equation becomes:
77 * yi + yj + xj - xi = (yi - xi) + (yj + xj)
78 *
79 * @param points - Array of [x, y] coordinates sorted by x-coordinate
80 * @param k - Maximum allowed difference between x-coordinates
81 * @returns Maximum value of the equation
82 */
83function findMaxValueOfEquation(points: number[][], k: number): number {
84 // Initialize result with negative infinity (using bit shift for large negative number)
85 let maxValue = -(1 << 30);
86
87 // Initialize max heap that stores [yi - xi, xi] pairs
88 // Heap is ordered by yi - xi in descending order (max heap)
89 heapInit((a: [number, number], b: [number, number]) => b[0] - a[0]);
90
91 // Process each point
92 for (const [currentX, currentY] of points) {
93 // Remove points that are too far from current point (distance > k)
94 while (heapSize() > 0 && currentX - heapTop()[1] > k) {
95 heapPop();
96 }
97
98 // If valid points exist, calculate equation value with current point
99 if (heapSize() > 0) {
100 // heapTop()[0] contains max(yi - xi) for valid points
101 // Equation value = (yi - xi) + (currentY + currentX)
102 maxValue = Math.max(maxValue, currentX + currentY + heapTop()[0]);
103 }
104
105 // Add current point to heap for future calculations
106 // Store [currentY - currentX, currentX] for this point
107 heapPush([currentY - currentX, currentX]);
108 }
109
110 return maxValue;
111}
112
Time and Space Complexity
Time Complexity: O(n log n)
where n
is the number of points.
- The code iterates through all
n
points once in the main loop. - For each point, we perform heap operations:
- The while loop pops elements from the heap when they violate the distance constraint
x - pq[0][1] > k
. In the worst case, all previously added elements might be popped, but each element is popped at most once throughout the entire execution. - Each
heappop
operation takesO(log n)
time. - Each
heappush
operation takesO(log n)
time.
- The while loop pops elements from the heap when they violate the distance constraint
- Since each point is pushed exactly once and popped at most once, the total number of heap operations is at most
2n
. - Therefore, the overall time complexity is
O(n log n)
.
Space Complexity: O(n)
- The priority queue
pq
can contain at mostn
elements in the worst case (when all points satisfy the distance constraint with each other). - Each element in the heap is a tuple
(x - y, x)
which takes constant space. - Therefore, the space complexity is
O(n)
.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Incorrect Heap Key Selection
A common mistake is using the wrong value as the heap's priority key. Developers might intuitively store (y - x, x)
instead of (x - y, x)
, thinking they want to maximize (y - x)
.
Why it's wrong: Python's heapq is a min-heap, so storing (y - x)
would give us the minimum (y - x)
value at the top, which is the opposite of what we need.
Solution: Store (x - y, x)
in the heap. The minimum (x - y)
value corresponds to the maximum (y - x)
value, which is what we need to maximize the equation.
2. Forgetting to Clean Expired Points
Developers might calculate the maximum value before removing points that violate the distance constraint:
# WRONG: Calculating before cleaning
if min_heap:
max_value = max(max_value, current_x + current_y - min_heap[0][0])
while min_heap and current_x - min_heap[0][1] > k:
heapq.heappop(min_heap)
Why it's wrong: This could use points that are beyond the allowed distance k
, leading to incorrect results.
Solution: Always clean the heap first, then calculate:
# CORRECT: Clean first, then calculate
while min_heap and current_x - min_heap[0][1] > k:
heapq.heappop(min_heap)
if min_heap:
max_value = max(max_value, current_x + current_y - min_heap[0][0])
3. Using Maximum Heap Instead of Minimum Heap
Some developers try to use a max-heap by negating values:
# Attempting to use max-heap by negating
heapq.heappush(min_heap, (-(y - x), x))
# Later retrieving with:
max_value = max(max_value, current_x + current_y + min_heap[0][0])
Why it's confusing: While this can work, it adds unnecessary complexity and makes the code harder to understand. The double negation can lead to sign errors.
Solution: Stick with the natural min-heap behavior and adjust the formula accordingly. Store (x - y)
and use -min_heap[0][0]
when calculating, which is clearer and less error-prone.
4. Incorrect Distance Calculation
A subtle error is using the wrong point's x-coordinate when checking the distance constraint:
# WRONG: Using the wrong index or variable while min_heap and min_heap[0][0] - current_x > k: # Using priority key instead of x heapq.heappop(min_heap)
Why it's wrong: min_heap[0][0]
contains (x - y)
, not the x-coordinate. The distance check needs the actual x-coordinate.
Solution: Always use min_heap[0][1]
for the x-coordinate:
# CORRECT: Using the x-coordinate from the tuple while min_heap and current_x - min_heap[0][1] > k: heapq.heappop(min_heap)
5. Not Initializing Maximum Value Properly
Starting with max_value = 0
or max_value = None
:
# WRONG: Could miss negative results max_value = 0
Why it's wrong: The maximum value could be negative if all valid pairs produce negative results. Starting with 0 would incorrectly return 0 instead of the actual negative maximum.
Solution: Initialize with negative infinity:
max_value = -inf # or float('-inf')
How does quick sort divide the problem into subproblems?
Recommended Readings
Queue Intro Think of the last time you stood in line to buy movie tickets The first person in line gets their ticket first and any newcomers join the end of the line This system where the first person to arrive is the first to be served is a queue in real
https assets algo monster cover_photos stack svg Sliding Window Maximum Monotonic Stack We have an array and a sliding window defined by a start index and an end index The sliding window moves from left of the array to right There are always k elements in the window The window
Monotonic Stack Deque Intro If you'd prefer a video div class responsive iframe iframe src https www youtube com embed Dq_ObZwTY_Q title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture web share allowfullscreen iframe div The word monotonic means a list or
Want a Structured Path to Master System Design Too? Don’t Miss This!