3572. Maximize Y‑Sum by Picking a Triplet of Distinct X‑Values
Problem Description
You have two integer arrays x
and y
, both with the same length n
. Your task is to select three different indices i
, j
, and k
from these arrays such that the values at these indices in array x
are all different from each other. Specifically:
x[i] ≠ x[j]
(the value at indexi
must be different from the value at indexj
)x[j] ≠ x[k]
(the value at indexj
must be different from the value at indexk
)x[k] ≠ x[i]
(the value at indexk
must be different from the value at indexi
)
Once you find three indices that satisfy these conditions, you want to maximize the sum y[i] + y[j] + y[k]
- the sum of the corresponding values from array y
at those same three indices.
The goal is to find the maximum possible sum of three y
values where their corresponding x
values are all distinct. If it's impossible to find three indices where all the x
values are different (for example, if array x
has fewer than 3 unique values), return -1
.
For example, if x = [1, 2, 3, 2]
and y = [10, 20, 30, 40]
, you could choose indices 0, 1, and 2 since x[0] = 1
, x[1] = 2
, and x[2] = 3
are all different. This would give you a sum of y[0] + y[1] + y[2] = 10 + 20 + 30 = 60
.
Intuition
To maximize the sum of three y
values while ensuring their corresponding x
values are all different, we need to be greedy - we want to pick the largest possible y
values.
Think about it this way: if we want the maximum sum, we should prioritize selecting indices with the highest y
values. The constraint is that the x
values at these indices must all be different from each other.
This leads us to a greedy strategy: sort all pairs (x[i], y[i])
by their y
values in descending order. Then, we can iterate through this sorted list and pick the first three pairs that have distinct x
values.
Why does this work? Because we're processing pairs in order of decreasing y
values, the first three pairs we find with distinct x
values will automatically give us the maximum possible sum. Any other combination would involve replacing at least one of our selected y
values with a smaller one (since we're going through them in descending order), which would decrease the total sum.
The key insight is that we don't need to check all possible combinations of three indices. By sorting and greedily selecting from the top, we guarantee we're getting the best possible sum. We use a hash set to keep track of which x
values we've already used, ensuring we only pick distinct ones.
If we go through the entire sorted list and can't find three distinct x
values, it means the problem has no valid solution, so we return -1
.
Learn more about Greedy, Sorting and Heap (Priority Queue) patterns.
Solution Approach
The implementation follows a sorting and greedy approach with a hash table to track selected values:
-
Create pairs and sort: First, we pair up the elements from arrays
x
andy
into a 2D arrayarr
where each element is a tuple(x[i], y[i])
. We then sort this array in descending order based on they
values usingarr.sort(key=lambda x: -x[1])
. The negative sign ensures descending order. -
Initialize tracking variables: We create a hash set
vis
to keep track of whichx
values we've already selected, and initializeans = 0
to accumulate the sum of selectedy
values. -
Greedy selection: We iterate through the sorted
arr
:- For each pair
(a, b)
wherea
is thex
value andb
is they
value - Check if
a
is already in ourvis
set (meaning we've already used thisx
value) - If
a
is already used, skip to the next pair withcontinue
- If
a
hasn't been used, add it tovis
and add its correspondingb
value to our running sumans
- For each pair
-
Check completion: After adding each new value, we check if
len(vis) == 3
, meaning we've successfully found three distinctx
values. If so, we immediately returnans
as our maximum sum. -
Handle invalid case: If the loop completes without finding three distinct
x
values (the array doesn't have enough uniquex
values), we return-1
.
The time complexity is O(n log n)
due to sorting, and the space complexity is O(n)
for storing the paired array and the hash set. The greedy approach guarantees optimality because we're always selecting the highest available y
values that satisfy our constraint of having distinct x
values.
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 a concrete example to illustrate the solution approach.
Given:
x = [1, 2, 1, 3, 2]
y = [50, 40, 30, 60, 20]
Step 1: Create pairs and sort by y values (descending)
First, we pair up the elements:
(1, 50)
from index 0(2, 40)
from index 1(1, 30)
from index 2(3, 60)
from index 3(2, 20)
from index 4
After sorting by y values in descending order:
(3, 60)
- highest y value(1, 50)
(2, 40)
(1, 30)
(2, 20)
- lowest y value
Step 2: Initialize tracking variables
vis = {}
(empty set to track used x values)ans = 0
(sum accumulator)
Step 3: Greedy selection
Iteration 1: Process (3, 60)
- x value = 3, not in
vis
- Add 3 to
vis
:vis = {3}
- Add 60 to sum:
ans = 60
- Check:
len(vis) = 1
(need more values)
Iteration 2: Process (1, 50)
- x value = 1, not in
vis
- Add 1 to
vis
:vis = {3, 1}
- Add 50 to sum:
ans = 110
- Check:
len(vis) = 2
(need one more)
Iteration 3: Process (2, 40)
- x value = 2, not in
vis
- Add 2 to
vis
:vis = {3, 1, 2}
- Add 40 to sum:
ans = 150
- Check:
len(vis) = 3
✓
Step 4: Return result We found three distinct x values (3, 1, 2) with the maximum possible sum of their corresponding y values: 60 + 50 + 40 = 150.
Note that we didn't need to check (1, 30)
or (2, 20)
because we already found our optimal solution. Even though these pairs exist, using them would require replacing one of our selected values with a smaller y value, which would decrease the total sum.
Solution Implementation
1class Solution:
2 def maxSumDistinctTriplet(self, x: List[int], y: List[int]) -> int:
3 # Create pairs of (x_value, y_value) from the two input lists
4 pairs = [(x_val, y_val) for x_val, y_val in zip(x, y)]
5
6 # Sort pairs in descending order by y_value (second element)
7 pairs.sort(key=lambda pair: -pair[1])
8
9 # Track which x_values have been selected
10 selected_x_values = set()
11 total_sum = 0
12
13 # Iterate through sorted pairs, selecting those with distinct x_values
14 for x_val, y_val in pairs:
15 # Skip if this x_value has already been selected
16 if x_val in selected_x_values:
17 continue
18
19 # Add this x_value to our selection
20 selected_x_values.add(x_val)
21 total_sum += y_val
22
23 # Return the sum once we have selected 3 distinct x_values
24 if len(selected_x_values) == 3:
25 return total_sum
26
27 # Return -1 if we couldn't find 3 distinct x_values
28 return -1
29
1class Solution {
2 public int maxSumDistinctTriplet(int[] x, int[] y) {
3 int n = x.length;
4
5 // Create a 2D array to store pairs of (x[i], y[i])
6 int[][] pairs = new int[n][2];
7 for (int i = 0; i < n; i++) {
8 pairs[i] = new int[] {x[i], y[i]};
9 }
10
11 // Sort pairs in descending order by y-values (second element)
12 // This ensures we process higher y-values first
13 Arrays.sort(pairs, (a, b) -> b[1] - a[1]);
14
15 // Track the sum of selected y-values
16 int totalSum = 0;
17
18 // Set to keep track of distinct x-values we've selected
19 Set<Integer> selectedXValues = new HashSet<>();
20
21 // Iterate through sorted pairs to find three distinct x-values
22 for (int i = 0; i < n; i++) {
23 int currentX = pairs[i][0];
24 int currentY = pairs[i][1];
25
26 // Try to add current x-value to the set
27 // If it's a new distinct x-value, include its y-value in the sum
28 if (selectedXValues.add(currentX)) {
29 totalSum += currentY;
30
31 // Check if we've found three distinct x-values
32 if (selectedXValues.size() == 3) {
33 return totalSum;
34 }
35 }
36 }
37
38 // Return -1 if we couldn't find three distinct x-values
39 return -1;
40 }
41}
42
1class Solution {
2public:
3 int maxSumDistinctTriplet(vector<int>& x, vector<int>& y) {
4 int n = x.size();
5
6 // Create pairs of (x_value, y_value) for easier manipulation
7 vector<array<int, 2>> pairs(n);
8 for (int i = 0; i < n; ++i) {
9 pairs[i] = {x[i], y[i]};
10 }
11
12 // Sort pairs by y-values in descending order (highest y-values first)
13 ranges::sort(pairs, [](const auto& a, const auto& b) {
14 return a[1] > b[1];
15 });
16
17 // Track the sum of selected y-values
18 int totalSum = 0;
19
20 // Keep track of which x-values we've already selected
21 unordered_set<int> selectedXValues;
22
23 // Iterate through pairs in order of decreasing y-values
24 for (int i = 0; i < n; ++i) {
25 int currentX = pairs[i][0];
26 int currentY = pairs[i][1];
27
28 // Try to insert current x-value; if successful (i.e., it's distinct)
29 if (selectedXValues.insert(currentX).second) {
30 // Add the corresponding y-value to our sum
31 totalSum += currentY;
32
33 // Check if we've found three distinct x-values
34 if (selectedXValues.size() == 3) {
35 return totalSum;
36 }
37 }
38 }
39
40 // Return -1 if we couldn't find three distinct x-values
41 return -1;
42 }
43};
44
1/**
2 * Finds the maximum sum of y-values for three distinct x-values.
3 * @param x - Array of x-coordinates
4 * @param y - Array of y-values corresponding to x-coordinates
5 * @returns Maximum sum of three y-values with distinct x-values, or -1 if not possible
6 */
7function maxSumDistinctTriplet(x: number[], y: number[]): number {
8 const n: number = x.length;
9
10 // Create pairs of [x-value, y-value] for easier manipulation
11 const pairs: [number, number][] = [];
12 for (let i = 0; i < n; i++) {
13 pairs.push([x[i], y[i]]);
14 }
15
16 // Sort pairs by y-value in descending order to prioritize higher y-values
17 pairs.sort((a: [number, number], b: [number, number]) => b[1] - a[1]);
18
19 // Track which x-values have been selected
20 const selectedXValues: Set<number> = new Set<number>();
21 let totalSum: number = 0;
22
23 // Iterate through sorted pairs and select up to 3 with distinct x-values
24 for (let i = 0; i < n; i++) {
25 const [currentX, currentY]: [number, number] = pairs[i];
26
27 // Only add if this x-value hasn't been selected yet
28 if (!selectedXValues.has(currentX)) {
29 selectedXValues.add(currentX);
30 totalSum += currentY;
31
32 // Return early if we've found 3 distinct x-values
33 if (selectedXValues.size === 3) {
34 return totalSum;
35 }
36 }
37 }
38
39 // Return -1 if we couldn't find 3 distinct x-values
40 return -1;
41}
42
Time and Space Complexity
Time Complexity: O(n × log n)
The dominant operation in this algorithm is the sorting step. The code creates a list of tuples from the two input arrays and sorts them based on the second element (y
values) in descending order using arr.sort(key=lambda x: -x[1])
. This sorting operation has a time complexity of O(n × log n)
where n
is the length of the input arrays. The subsequent iteration through the sorted array takes O(n)
time in the worst case, but since it terminates early when 3 distinct elements are found, it's at most O(n)
. The overall time complexity is therefore O(n × log n)
.
Space Complexity: O(n)
The algorithm creates additional data structures that contribute to space complexity:
- The
arr
list containing tuples of(x[i], y[i])
pairs requiresO(n)
space - The
vis
set stores at most 3 elements (since the function returns when the set size reaches 3), which isO(1)
in terms of the problem constraints - The sorting operation may use additional
O(log n)
space for the sorting algorithm's recursion stack (depending on the implementation)
The overall space complexity is O(n)
as the array of tuples dominates the space usage.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
Pitfall 1: Assuming indices must be consecutive or ordered
A common misunderstanding is thinking that the three indices i, j, and k must be in some specific order (like i < j < k) or must be consecutive. The problem actually allows any three different indices in any order.
Why this matters: If you incorrectly add ordering constraints, you might miss the optimal solution. For example, with x = [1, 2, 3]
and y = [30, 10, 20]
, the optimal indices are (0, 2, 1) giving sum 60, not (0, 1, 2) giving sum 60 in this case, but in other cases the order could matter significantly.
Solution: The provided approach correctly handles this by considering all elements regardless of their original index positions after sorting.
Pitfall 2: Not handling duplicate x values properly
The most critical pitfall is incorrectly handling cases where the same x value appears multiple times with different y values. Consider x = [1, 1, 2, 3]
and y = [100, 10, 20, 30]
.
Why this matters: You might be tempted to keep multiple pairs with the same x value, but the constraint requires all three selected x values to be distinct. The greedy approach must select only ONE occurrence of each unique x value - specifically, the one with the highest y value.
Solution: The code correctly handles this by:
- Sorting pairs by y values in descending order
- Using a set to track already-selected x values
- Skipping any pair whose x value has already been selected
Pitfall 3: Early termination without checking feasibility
Some might try to optimize by taking the first three elements from the sorted array without checking if their x values are distinct.
Example problematic code:
# WRONG APPROACH pairs.sort(key=lambda pair: -pair[1]) return pairs[0][1] + pairs[1][1] + pairs[2][1] # Doesn't check x values!
Why this matters: With x = [1, 1, 1, 2]
and y = [100, 90, 80, 10]
, this would incorrectly return 270 (100+90+80) even though all three top y values correspond to the same x value (1).
Solution: The provided code correctly checks each x value against the set of already-selected values before including it in the sum.
Pitfall 4: Not returning -1 for insufficient unique values
Forgetting to handle the case where there are fewer than 3 unique x values in the entire array.
Why this matters: With x = [1, 1, 2, 2]
and y = [10, 20, 30, 40]
, there are only 2 unique x values (1 and 2), making it impossible to select 3 distinct ones.
Solution: The code correctly returns -1 when the loop completes without finding 3 distinct x values.
The three-steps of Depth First Search are:
- Identify states;
- Draw the state-space tree;
- DFS on the state-space tree.
Recommended Readings
Greedy Introduction div class responsive iframe iframe src https www youtube com embed WTslqPbj7I title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture web share allowfullscreen iframe div When do we use greedy Greedy algorithms tend to solve optimization problems Typically they will ask you to calculate the max min of some value Commonly you may see this phrased in the problem as max min longest shortest largest smallest etc These keywords can be identified by just scanning
Sorting Summary Comparisons We presented quite a few sorting algorithms and it is essential to know the advantages and disadvantages of each one The basic algorithms are easy to visualize and easy to learn for beginner programmers because of their simplicity As such they will suffice if you don't know any advanced
https assets algo monster cover_photos heap svg Priority Queue and Heap What is the relationship between priority queue and heap Priority Queue is an Abstract Data Type and Heap is the concrete data structure we use to implement a priority queue Priority Queue A priority queue is a data structure
Want a Structured Path to Master System Design Too? Don’t Miss This!