1131. Maximum of Absolute Value Expression
Problem Description
You are given two arrays of integers arr1
and arr2
that have equal lengths. Your task is to find the maximum value of the expression:
|arr1[i] - arr1[j]| + |arr2[i] - arr2[j]| + |i - j|
where you need to consider all possible pairs of indices i
and j
such that 0 <= i, j < arr1.length
.
Breaking down the expression:
|arr1[i] - arr1[j]|
represents the absolute difference between elements at positionsi
andj
in the first array|arr2[i] - arr2[j]|
represents the absolute difference between elements at positionsi
andj
in the second array|i - j|
represents the absolute difference between the indices themselves
You need to evaluate this expression for all possible pairs of indices and return the maximum value found.
For example, if you have arr1 = [1, 2, 3]
and arr2 = [4, 5, 6]
, you would evaluate the expression for all combinations like (i=0, j=0), (i=0, j=1), (i=0, j=2), (i=1, j=0), etc., and return the largest result.
Intuition
The key insight is recognizing that dealing with absolute values directly is complex, but we can transform them into simpler expressions by considering all possible sign combinations.
Let's denote x_i = arr1[i]
and y_i = arr2[i]
. Without loss of generality, we can assume i >= j
(since if i < j
, we can swap them and get the same result due to the absolute values).
When i >= j
, the expression becomes:
|x_i - x_j| + |y_i - y_j| + (i - j)
The absolute value |x_i - x_j|
can be either (x_i - x_j)
or -(x_i - x_j)
, depending on which value is larger. Similarly, |y_i - y_j|
can be either (y_i - y_j)
or -(y_i - y_j)
.
This gives us 4 possible combinations:
(x_i - x_j) + (y_i - y_j) + (i - j) = (x_i + y_i + i) - (x_j + y_j + j)
(x_i - x_j) - (y_i - y_j) + (i - j) = (x_i - y_i + i) - (x_j - y_j + j)
-(x_i - x_j) + (y_i - y_j) + (i - j) = (-x_i + y_i + i) - (-x_j + y_j + j)
-(x_i - x_j) - (y_i - y_j) + (i - j) = (-x_i - y_i + i) - (-x_j - y_j + j)
Notice the pattern: each expression is of the form (a*x_i + b*y_i + i) - (a*x_j + b*y_j + j)
where a, b ∈ {-1, 1}
.
To maximize this difference, we need to find the maximum and minimum values of a*x_i + b*y_i + i
for each combination of a
and b
. The maximum difference will be max_value - min_value
for each sign combination.
By iterating through all four sign combinations and tracking the maximum and minimum values of the transformed expression for each index, we can find the overall maximum in a single pass through the arrays.
Learn more about Math patterns.
Solution Approach
Based on our mathematical transformation, we need to evaluate a * x_i + b * y_i + i
for all combinations where a, b ∈ {-1, 1}
. This gives us 4 combinations: (1, 1)
, (1, -1)
, (-1, 1)
, and (-1, -1)
.
The implementation uses a clever way to iterate through these sign combinations. The dirs
tuple (1, -1, -1, 1, 1)
is used with pairwise
to generate consecutive pairs: (1, -1)
, (-1, -1)
, (-1, 1)
, and (1, 1)
, which represent our (a, b)
combinations.
Here's how the algorithm works:
-
Initialize variables: Set
ans = -inf
to track the maximum result across all sign combinations. -
Iterate through sign combinations: For each pair
(a, b)
from thedirs
tuple:- Initialize
mx = -inf
to track the maximum value ofa * x + b * y + i
- Initialize
mi = inf
to track the minimum value ofa * x + b * y + i
- Initialize
-
Process each index: For each index
i
and corresponding values(x, y)
from(arr1[i], arr2[i])
:- Calculate the expression value:
a * x + b * y + i
- Update
mx
to be the maximum seen so far - Update
mi
to be the minimum seen so far - Update
ans
withmx - mi
, which represents the maximum difference for the current sign combination
- Calculate the expression value:
-
Return the result: After checking all four sign combinations,
ans
contains the maximum value of the original expression.
The algorithm efficiently computes the answer in O(n)
time by:
- Making a single pass through the arrays for each sign combination (4 passes total)
- Maintaining running maximum and minimum values instead of comparing all pairs
- Using the mathematical transformation to avoid dealing with absolute values directly
The space complexity is O(1)
as we only use a constant amount of extra variables regardless of input size.
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 small example with arr1 = [1, 3]
and arr2 = [2, 5]
.
We need to find the maximum value of |arr1[i] - arr1[j]| + |arr2[i] - arr2[j]| + |i - j|
.
Step 1: Understand what we're calculating
For each sign combination (a, b)
, we calculate a * arr1[i] + b * arr2[i] + i
for each index i
, then find the maximum difference between any two values.
Step 2: Process each sign combination
Let's trace through each combination:
Combination 1: (a=1, b=-1)
- For i=0:
1*1 + (-1)*2 + 0 = 1 - 2 + 0 = -1
- For i=1:
1*3 + (-1)*5 + 1 = 3 - 5 + 1 = -1
- Maximum = -1, Minimum = -1
- Difference = -1 - (-1) = 0
Combination 2: (a=-1, b=-1)
- For i=0:
(-1)*1 + (-1)*2 + 0 = -1 - 2 + 0 = -3
- For i=1:
(-1)*3 + (-1)*5 + 1 = -3 - 5 + 1 = -7
- Maximum = -3, Minimum = -7
- Difference = -3 - (-7) = 4
Combination 3: (a=-1, b=1)
- For i=0:
(-1)*1 + 1*2 + 0 = -1 + 2 + 0 = 1
- For i=1:
(-1)*3 + 1*5 + 1 = -3 + 5 + 1 = 3
- Maximum = 3, Minimum = 1
- Difference = 3 - 1 = 2
Combination 4: (a=1, b=1)
- For i=0:
1*1 + 1*2 + 0 = 1 + 2 + 0 = 3
- For i=1:
1*3 + 1*5 + 1 = 3 + 5 + 1 = 9
- Maximum = 9, Minimum = 3
- Difference = 9 - 3 = 6
Step 3: Find the maximum
The maximum difference across all combinations is 6.
Verification: Let's verify by checking the original expression for pairs (i=0, j=1) and (i=1, j=0):
- For (i=1, j=0):
|3-1| + |5-2| + |1-0| = 2 + 3 + 1 = 6
✓ - For (i=0, j=1):
|1-3| + |2-5| + |0-1| = 2 + 3 + 1 = 6
✓
The algorithm correctly identifies that the maximum value is 6, which occurs when comparing indices 0 and 1. The transformation handles all the absolute value cases automatically by considering different sign combinations.
Solution Implementation
1from typing import List
2from itertools import pairwise
3
4class Solution:
5 def maxAbsValExpr(self, arr1: List[int], arr2: List[int]) -> int:
6 # Direction coefficients for handling absolute value cases
7 # Each pair represents coefficients for arr1[i] and arr2[i]
8 # The 4 cases handle all combinations when removing absolute values
9 direction_coefficients = (1, -1, -1, 1, 1)
10
11 max_result = float('-inf')
12
13 # Iterate through pairs of coefficients using pairwise
14 # This gives us (1, -1), (-1, -1), (-1, 1), (1, 1)
15 for coeff_arr1, coeff_arr2 in pairwise(direction_coefficients):
16 max_value = float('-inf')
17 min_value = float('inf')
18
19 # Process each index and corresponding values from both arrays
20 for index, (value1, value2) in enumerate(zip(arr1, arr2)):
21 # Calculate the expression for current coefficients
22 current_expression = coeff_arr1 * value1 + coeff_arr2 * value2 + index
23
24 # Track maximum and minimum values for this coefficient combination
25 max_value = max(max_value, current_expression)
26 min_value = min(min_value, current_expression)
27
28 # Update the global maximum with the difference
29 # The difference represents the maximum absolute value expression
30 max_result = max(max_result, max_value - min_value)
31
32 return max_result
33
1class Solution {
2 public int maxAbsValExpr(int[] arr1, int[] arr2) {
3 // Direction coefficients for the 4 cases of removing absolute values
4 // Each pair (dirs[k], dirs[k+1]) represents coefficients for arr1 and arr2
5 int[] directions = {1, -1, -1, 1, 1};
6
7 // Initialize constants
8 final int INFINITY = 1 << 30; // Large value for initialization (2^30)
9 int maxResult = -INFINITY; // Track the maximum result across all cases
10 int arrayLength = arr1.length;
11
12 // Iterate through 4 different sign combinations
13 // These correspond to the 4 ways to remove absolute values from the expression
14 for (int caseIndex = 0; caseIndex < 4; ++caseIndex) {
15 // Get coefficients for current case
16 int coefficientArr1 = directions[caseIndex];
17 int coefficientArr2 = directions[caseIndex + 1];
18
19 // Track maximum and minimum values for current case
20 int maxValue = -INFINITY;
21 int minValue = INFINITY;
22
23 // Process each element in the arrays
24 for (int i = 0; i < arrayLength; ++i) {
25 // Calculate the expression value for current element and case
26 // Formula: a * arr1[i] + b * arr2[i] + i
27 int currentValue = coefficientArr1 * arr1[i] + coefficientArr2 * arr2[i] + i;
28
29 // Update maximum and minimum values seen so far
30 maxValue = Math.max(maxValue, currentValue);
31 minValue = Math.min(minValue, currentValue);
32
33 // Update the overall maximum result
34 // The difference (max - min) gives us the maximum absolute expression value
35 maxResult = Math.max(maxResult, maxValue - minValue);
36 }
37 }
38
39 return maxResult;
40 }
41}
42
1class Solution {
2public:
3 int maxAbsValExpr(vector<int>& arr1, vector<int>& arr2) {
4 // Direction coefficients for the 4 cases when expanding absolute values
5 // Each pair (directions[k], directions[k+1]) represents coefficients for arr1 and arr2
6 int directions[5] = {1, -1, -1, 1, 1};
7
8 const int INF = 1 << 30; // Large value representing infinity
9 int maxResult = -INF; // Initialize result to negative infinity
10 int n = arr1.size();
11
12 // Try all 4 combinations of signs when expanding the absolute value expression
13 // The expression |arr1[i] - arr1[j]| + |arr2[i] - arr2[j]| + |i - j|
14 // can be rewritten as one of 4 forms by considering sign combinations
15 for (int k = 0; k < 4; ++k) {
16 int coeff1 = directions[k]; // Coefficient for arr1
17 int coeff2 = directions[k + 1]; // Coefficient for arr2
18
19 int maxValue = -INF; // Track maximum value of the expression
20 int minValue = INF; // Track minimum value of the expression
21
22 // For each index i, calculate the expression value
23 // Expression: coeff1 * arr1[i] + coeff2 * arr2[i] + i
24 for (int i = 0; i < n; ++i) {
25 int currentValue = coeff1 * arr1[i] + coeff2 * arr2[i] + i;
26 maxValue = max(maxValue, currentValue);
27 minValue = min(minValue, currentValue);
28
29 // The maximum difference gives us the maximum absolute value
30 maxResult = max(maxResult, maxValue - minValue);
31 }
32 }
33
34 return maxResult;
35 }
36};
37
1/**
2 * Finds the maximum value of |arr1[i] - arr1[j]| + |arr2[i] - arr2[j]| + |i - j|
3 * for all pairs of indices i and j.
4 *
5 * The key insight is that the absolute value expression can be expanded into 4 cases
6 * based on the signs of (arr1[i] - arr1[j]), (arr2[i] - arr2[j]), and (i - j).
7 * Each case becomes a linear combination that can be optimized by tracking min/max values.
8 *
9 * @param arr1 - First input array
10 * @param arr2 - Second input array
11 * @returns Maximum value of the expression across all pairs
12 */
13function maxAbsValExpr(arr1: number[], arr2: number[]): number {
14 // Direction coefficients for the 4 possible sign combinations
15 // These represent: (1,1), (-1,-1), (-1,1), (1,-1)
16 const directionCoefficients: number[] = [1, -1, -1, 1, 1];
17
18 // Initialize with negative infinity as we're looking for maximum
19 const NEGATIVE_INFINITY: number = -(1 << 30);
20 let maxResult: number = NEGATIVE_INFINITY;
21
22 // Process each of the 4 sign combinations
23 for (let signCase: number = 0; signCase < 4; signCase++) {
24 // Get coefficients for arr1[i] and arr2[i] in this case
25 const coefficientA: number = directionCoefficients[signCase];
26 const coefficientB: number = directionCoefficients[signCase + 1];
27
28 // Track maximum and minimum values for current linear combination
29 let maxValue: number = NEGATIVE_INFINITY;
30 let minValue: number = 1 << 30; // Positive infinity
31
32 // Iterate through all indices
33 for (let index: number = 0; index < arr1.length; index++) {
34 const value1: number = arr1[index];
35 const value2: number = arr2[index];
36
37 // Calculate linear combination: a*arr1[i] + b*arr2[i] + i
38 const currentCombination: number = coefficientA * value1 + coefficientB * value2 + index;
39
40 // Update maximum and minimum for this combination
41 maxValue = Math.max(maxValue, currentCombination);
42 minValue = Math.min(minValue, currentCombination);
43
44 // Update global maximum with the difference (represents the original expression)
45 maxResult = Math.max(maxResult, maxValue - minValue);
46 }
47 }
48
49 return maxResult;
50}
51
Time and Space Complexity
Time Complexity: O(n)
The code iterates through 4 direction pairs (from pairwise(dirs)
which generates 4 pairs). For each direction pair, it performs a single pass through both arrays simultaneously using enumerate(zip(arr1, arr2))
, where n
is the length of the arrays. Inside the inner loop, all operations (max
, min
, arithmetic operations) are O(1)
. Therefore, the total time complexity is O(4 * n) = O(n)
.
Space Complexity: O(1)
The algorithm uses only a constant amount of extra space:
dirs
tuple with 5 elements:O(1)
- Variables
ans
,mx
,mi
,a
,b
,i
,x
,y
:O(1)
- The
pairwise
function generates pairs on-the-fly without storing all pairs at once - The
zip
function also creates an iterator that doesn't store all pairs in memory
No additional data structures that scale with input size are used, resulting in O(1)
space complexity.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Incorrect Handling of Absolute Value Cases
Pitfall: A common mistake is trying to handle the absolute values directly or missing some of the sign combinations when transforming the expression. The expression |arr1[i] - arr1[j]| + |arr2[i] - arr2[j]| + |i - j|
can be expanded into 8 different cases based on the signs, but since i < j
can be assumed without loss of generality (due to symmetry), we only need 4 cases.
Why it happens: Developers might try to enumerate all 8 cases or incorrectly reduce them, leading to wrong answers.
Solution: Recognize that for any pair (i, j)
, we can assume i < j
without loss of generality. This reduces the expression to:
(arr1[j] - arr1[i]) + (arr2[j] - arr2[i]) + (j - i)
→ coefficients(1, 1)
(arr1[j] - arr1[i]) - (arr2[j] - arr2[i]) + (j - i)
→ coefficients(1, -1)
-(arr1[j] - arr1[i]) + (arr2[j] - arr2[i]) + (j - i)
→ coefficients(-1, 1)
-(arr1[j] - arr1[i]) - (arr2[j] - arr2[i]) + (j - i)
→ coefficients(-1, -1)
2. Brute Force O(n²) Approach Leading to Time Limit Exceeded
Pitfall: The naive approach of checking all pairs directly:
max_val = 0
for i in range(len(arr1)):
for j in range(len(arr1)):
val = abs(arr1[i] - arr1[j]) + abs(arr2[i] - arr2[j]) + abs(i - j)
max_val = max(max_val, val)
return max_val
Why it happens: The problem statement naturally suggests comparing all pairs, which leads to an O(n²) solution.
Solution: Transform the problem mathematically to recognize that for each sign combination, we're looking for the maximum difference between expressions of the form a*arr1[i] + b*arr2[i] + i
. This allows us to compute the result in a single pass for each combination, reducing complexity to O(n).
3. Forgetting to Initialize Max/Min Values Properly
Pitfall: Using incorrect initial values like 0
for maximum or minimum tracking:
max_value = 0 # Wrong! Should be float('-inf') min_value = 0 # Wrong! Should be float('inf')
Why it happens: Arrays might contain negative values, and the expression could evaluate to negative numbers during intermediate steps.
Solution: Always initialize:
max_value = float('-inf')
for tracking maximumsmin_value = float('inf')
for tracking minimums
4. Misunderstanding the Index Component
Pitfall: Forgetting to include the index i
in the expression calculation or treating it as j - i
instead of just i
or j
:
# Wrong: forgetting the index current_expression = coeff_arr1 * value1 + coeff_arr2 * value2 # Wrong: using difference when we should use the index directly current_expression = coeff_arr1 * value1 + coeff_arr2 * value2 + (j - i)
Why it happens: The mathematical transformation shows that we need a*arr1[j] + b*arr2[j] + j - (a*arr1[i] + b*arr2[i] + i)
, so each term needs its own index added.
Solution: Include the index in the expression calculation:
current_expression = coeff_arr1 * value1 + coeff_arr2 * value2 + index
Consider the classic dynamic programming of longest increasing subsequence:
Find the length of the longest subsequence of a given sequence such that all elements of the subsequence are sorted in increasing order.
For example, the length of LIS for [50, 3, 10, 7, 40, 80]
is 4
and LIS is
[3, 7, 40, 80]
.
What is the recurrence relation?
Recommended Readings
Math for Technical Interviews How much math do I need to know for technical interviews The short answer is about high school level math Computer science is often associated with math and some universities even place their computer science department under the math faculty However the reality is that you
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Don’t Miss This!