Facebook Pixel

1913. Maximum Product Difference Between Two Pairs

Problem Description

You are given an integer array nums and need to find the maximum product difference between two pairs of numbers from the array.

The product difference between two pairs (a, b) and (c, d) is calculated as (a * b) - (c * d).

Your task is to select four distinct indices w, x, y, and z from the array such that the product difference between pairs (nums[w], nums[x]) and (nums[y], nums[z]) is as large as possible.

For example, if you have pairs (5, 6) and (2, 7), the product difference would be (5 * 6) - (2 * 7) = 30 - 14 = 16.

The solution approach leverages the fact that to maximize the product difference, you want:

  • The first product (a * b) to be as large as possible - this is achieved by multiplying the two largest numbers in the array
  • The second product (c * d) to be as small as possible - this is achieved by multiplying the two smallest numbers in the array

By sorting the array, you can easily access:

  • The two largest elements at positions nums[-1] and nums[-2]
  • The two smallest elements at positions nums[0] and nums[1]

The maximum product difference is then nums[-1] * nums[-2] - nums[0] * nums[1].

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

To maximize the expression (a * b) - (c * d), we need to think about what makes this difference as large as possible.

This expression becomes largest when:

  1. The first product (a * b) is maximized
  2. The second product (c * d) is minimized

Since we're dealing with products of two numbers, let's think about when products are large or small:

  • A product of two numbers is largest when both numbers are as large as possible
  • A product of two numbers is smallest when both numbers are as small as possible (assuming positive numbers)

This leads us to a key insight: we should pair the two largest numbers together for the first product, and pair the two smallest numbers together for the second product.

Why not mix large and small numbers? Consider if we paired a large number with a small number - this would give us a medium-sized product. Using this for either the first or second product would not be optimal:

  • If used as (a * b), it's smaller than the product of the two largest numbers
  • If used as (c * d), it's larger than the product of the two smallest numbers

Therefore, the optimal strategy is straightforward:

  • Find the two largest elements in the array and multiply them
  • Find the two smallest elements in the array and multiply them
  • Subtract the smaller product from the larger product

Sorting the array makes this trivial to implement - after sorting, the two smallest elements are at the beginning nums[0] and nums[1], while the two largest are at the end nums[-1] and nums[-2].

Learn more about Sorting patterns.

Solution Approach

The implementation is straightforward and follows directly from our intuition:

  1. Sort the array: We use Python's built-in sort() method to arrange all elements in ascending order. This takes O(n log n) time complexity.

  2. Access the required elements: After sorting:

    • The two smallest elements are at indices 0 and 1
    • The two largest elements are at indices -1 and -2 (using Python's negative indexing)
  3. Calculate the maximum product difference:

    • Compute the product of the two largest numbers: nums[-1] * nums[-2]
    • Compute the product of the two smallest numbers: nums[0] * nums[1]
    • Return their difference: nums[-1] * nums[-2] - nums[0] * nums[1]

The complete solution in just three lines:

class Solution:
    def maxProductDifference(self, nums: List[int]) -> int:
        nums.sort()
        return nums[-1] * nums[-2] - nums[0] * nums[1]

Time Complexity: O(n log n) due to the sorting operation, where n is the length of the input array.

Space Complexity: O(1) if we consider the sorting is done in-place (though technically Python's sort uses O(n) space in the worst case).

An alternative approach without full sorting could use a heap or simply find the two maximum and two minimum values in a single pass, which would reduce time complexity to O(n), but the sorting approach is cleaner and sufficient for most practical purposes.

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through the solution with a concrete example to see how it works.

Example Input: nums = [4, 2, 5, 9, 7, 4, 8]

Step 1: Sort the array After sorting: nums = [2, 4, 4, 5, 7, 8, 9]

Step 2: Identify the key elements

  • Two smallest elements: nums[0] = 2 and nums[1] = 4
  • Two largest elements: nums[-2] = 8 and nums[-1] = 9

Step 3: Calculate the products

  • Product of two largest: 9 × 8 = 72
  • Product of two smallest: 2 × 4 = 8

Step 4: Find the maximum product difference

  • Maximum product difference = 72 - 8 = 64

Let's verify why this is optimal by considering other possible pairings:

  • If we paired (9, 7) and (2, 4): 63 - 8 = 55 (smaller than 64)
  • If we paired (9, 5) and (2, 4): 45 - 8 = 37 (smaller than 64)
  • If we paired (8, 7) and (4, 4): 56 - 16 = 40 (smaller than 64)

As we can see, pairing the two largest numbers together and the two smallest numbers together gives us the maximum possible product difference of 64.

The beauty of this approach is that sorting automatically organizes our array so that we can directly access these optimal pairs without having to check all possible combinations.

Solution Implementation

1class Solution:
2    def maxProductDifference(self, nums: List[int]) -> int:
3        """
4        Calculate the maximum product difference between two pairs.
5      
6        The product difference between two pairs (a, b) and (c, d) is defined as (a * b) - (c * d).
7        To maximize this difference, we need to maximize (a * b) and minimize (c * d).
8        This is achieved by using the two largest numbers for the first pair 
9        and the two smallest numbers for the second pair.
10      
11        Args:
12            nums: List of integers with at least 4 elements
13          
14        Returns:
15            Maximum product difference between two pairs
16        """
17        # Sort the array to easily access smallest and largest elements
18        nums.sort()
19      
20        # Calculate the product difference:
21        # - Multiply the two largest numbers (last two elements after sorting)
22        # - Subtract the product of the two smallest numbers (first two elements)
23        max_product = nums[-1] * nums[-2]
24        min_product = nums[0] * nums[1]
25      
26        return max_product - min_product
27
1class Solution {
2    /**
3     * Finds the maximum product difference between two pairs in the array.
4     * The maximum product difference is defined as:
5     * (max1 * max2) - (min1 * min2)
6     * where max1 and max2 are the two largest elements,
7     * and min1 and min2 are the two smallest elements.
8     * 
9     * @param nums the input array of integers
10     * @return the maximum product difference
11     */
12    public int maxProductDifference(int[] nums) {
13        // Sort the array in ascending order
14        Arrays.sort(nums);
15      
16        // Get the array length
17        int n = nums.length;
18      
19        // Calculate the product difference:
20        // Product of two largest elements minus product of two smallest elements
21        int largestProduct = nums[n - 1] * nums[n - 2];
22        int smallestProduct = nums[0] * nums[1];
23      
24        return largestProduct - smallestProduct;
25    }
26}
27
1class Solution {
2public:
3    int maxProductDifference(vector<int>& nums) {
4        // Sort the array in ascending order
5        sort(nums.begin(), nums.end());
6      
7        // Get the size of the array
8        int n = nums.size();
9      
10        // Calculate the maximum product difference:
11        // - Maximum product: two largest elements (at indices n-1 and n-2)
12        // - Minimum product: two smallest elements (at indices 0 and 1)
13        // - Return the difference between max and min products
14        return nums[n - 1] * nums[n - 2] - nums[0] * nums[1];
15    }
16};
17
1/**
2 * Finds the maximum product difference between two pairs in an array.
3 * The product difference is defined as (a * b) - (c * d) where a, b, c, d are elements from the array.
4 * To maximize this difference, we multiply the two largest numbers and subtract the product of the two smallest numbers.
5 * 
6 * @param nums - Array of integers (must contain at least 4 elements)
7 * @returns The maximum product difference
8 */
9function maxProductDifference(nums: number[]): number {
10    // Sort the array in ascending order
11    nums.sort((a: number, b: number) => a - b);
12  
13    // Get the length of the sorted array
14    const length: number = nums.length;
15  
16    // Calculate the maximum product difference:
17    // Product of two largest numbers minus product of two smallest numbers
18    const maxDifference: number = nums[length - 1] * nums[length - 2] - nums[0] * nums[1];
19  
20    return maxDifference;
21}
22

Time and Space Complexity

Time Complexity: O(n log n), where n is the length of the input array nums. This is because the code uses Python's built-in sort() method, which implements Timsort algorithm with a time complexity of O(n log n) in the average and worst cases.

Space Complexity: O(1) or O(n) depending on the sorting algorithm implementation. Python's sort() method sorts the list in-place, so it doesn't create a new list. However, Timsort requires O(n) auxiliary space in the worst case for its merge operations. If we consider only the extra space used by our code (not counting the sorting algorithm's internal space), it would be O(1) since we only use a constant amount of extra variables to store the result.

Alternative Approach: The problem could be solved in O(n) time by finding the two largest and two smallest numbers in a single pass through the array, which would use O(1) space, making it more efficient than the sorting approach.

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Not Considering Negative Numbers

A critical pitfall is assuming that the smallest product always comes from the two smallest positive numbers. When the array contains negative numbers, the product of two large negative numbers can actually be positive and large!

Example Problem Case:

  • Input: nums = [-5, -4, 1, 2, 3, 10]
  • After sorting: [-5, -4, 1, 2, 3, 10]
  • Current approach: 10 * 3 - (-5) * (-4) = 30 - 20 = 10
  • But wait! (-5) * (-4) = 20 is positive, which increases the second term and reduces our difference.

Why the Solution Still Works: Fortunately, the sorting approach handles this correctly! When we sort the array:

  • The two most negative numbers (if they exist) will be at the beginning
  • Their product will be positive and large
  • But we're subtracting this product, so a larger positive product here actually reduces our final answer
  • This is exactly what we want - we're still minimizing the impact of the second product on our difference

2. Modifying the Original Array

The sort() method modifies the input array in-place, which might not be acceptable in some contexts where the original array order needs to be preserved.

Solution:

class Solution:
    def maxProductDifference(self, nums: List[int]) -> int:
        # Create a copy to avoid modifying the original array
        sorted_nums = sorted(nums)  # sorted() returns a new list
        return sorted_nums[-1] * sorted_nums[-2] - sorted_nums[0] * sorted_nums[1]

3. Assuming Array Has At Least 4 Elements

The problem assumes the array has at least 4 distinct elements, but in production code, you might want to validate this.

Solution with Validation:

class Solution:
    def maxProductDifference(self, nums: List[int]) -> int:
        if len(nums) < 4:
            raise ValueError("Array must have at least 4 elements")
      
        nums.sort()
        return nums[-1] * nums[-2] - nums[0] * nums[1]

4. Overflow Concerns

In languages with fixed integer sizes, multiplying large numbers could cause overflow. Python handles arbitrary precision integers automatically, but in other languages like C++ or Java, you might need to use long long or Long types.

5. Inefficiency for Large Arrays When Only 4 Elements Matter

Sorting the entire array takes O(n log n) time when we only need the two largest and two smallest elements. For very large arrays, this could be inefficient.

Optimized O(n) Solution:

class Solution:
    def maxProductDifference(self, nums: List[int]) -> int:
        # Find two largest and two smallest in single pass
        max1 = max2 = float('-inf')
        min1 = min2 = float('inf')
      
        for num in nums:
            if num > max1:
                max2 = max1
                max1 = num
            elif num > max2:
                max2 = num
          
            if num < min1:
                min2 = min1
                min1 = num
            elif num < min2:
                min2 = num
      
        return max1 * max2 - min1 * min2

This approach runs in O(n) time and O(1) space, making it more efficient for large arrays.

Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

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

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More