1464. Maximum Product of Two Elements in an Array
Problem Description
You are given an array of integers called nums
. Your task is to select two different indices i
and j
from this array and calculate the product (nums[i]-1) * (nums[j]-1)
. You need to find and return the maximum possible value of this product.
In other words, you need to:
- Pick any two different elements from the array
- Subtract 1 from each of these elements
- Multiply the results together
- Find the combination that gives you the largest product
For example, if you have an array [3, 4, 5, 2]
, you could choose:
- Elements 3 and 4:
(3-1) * (4-1) = 2 * 3 = 6
- Elements 3 and 5:
(3-1) * (5-1) = 2 * 4 = 8
- Elements 3 and 2:
(3-1) * (2-1) = 2 * 1 = 2
- Elements 4 and 5:
(4-1) * (5-1) = 3 * 4 = 12
- Elements 4 and 2:
(4-1) * (2-1) = 3 * 1 = 3
- Elements 5 and 2:
(5-1) * (2-1) = 4 * 1 = 4
The maximum product would be 12, which comes from choosing elements 4 and 5.
Intuition
To maximize the product (nums[i]-1) * (nums[j]-1)
, we need to think about what makes a product large. Since we're multiplying two values together, we want both values to be as large as possible.
After subtracting 1 from each element, the largest possible values come from the largest elements in the original array. For instance, if we have elements 10 and 8 in the array, after subtracting 1, we get 9 and 7, which when multiplied give us 63. This would be much larger than using smaller elements like 3 and 4, which would give us (3-1) * (4-1) = 2 * 3 = 6
.
The key insight is that to maximize (a-1) * (b-1)
, we should choose the two largest elements in the array. This is because:
- Larger numbers remain large even after subtracting 1
- The product of two large numbers is maximized when both numbers are as large as possible
However, the given solution takes a brute force approach by checking all possible pairs. It iterates through every combination of two different elements, calculates (nums[i]-1) * (nums[j]-1)
for each pair, and keeps track of the maximum value found. While this guarantees finding the correct answer, it's not the most efficient approach.
A more optimal solution would be to simply find the two largest elements in the array and calculate their product after subtracting 1 from each. This would reduce the time complexity from O(n²)
to O(n)
.
Learn more about Sorting and Heap (Priority Queue) patterns.
Solution Approach
The implementation uses a brute force approach with nested loops to examine all possible pairs of elements in the array.
Algorithm Steps:
-
Initialize a variable
ans
to 0 to keep track of the maximum product found so far. -
Use
enumerate()
to iterate through the array with both indexi
and valuea
:- The outer loop picks the first element of each pair
-
For each element
a
at positioni
, iterate through all elements that come after it usingnums[i + 1:]
:- This ensures we only check each pair once and don't compare an element with itself
- The slice
nums[i + 1:]
gives us all elements from positioni+1
to the end of the array
-
For each pair
(a, b)
, calculate the product(a - 1) * (b - 1)
-
Update
ans
usingmax(ans, (a - 1) * (b - 1))
to keep the maximum value seen so far -
After checking all pairs, return the maximum product stored in
ans
Example Walkthrough:
For nums = [3, 4, 5, 2]
:
- When
i=0, a=3
: Check pairs with[4, 5, 2]
(3-1) * (4-1) = 6
(3-1) * (5-1) = 8
(3-1) * (2-1) = 2
- When
i=1, a=4
: Check pairs with[5, 2]
(4-1) * (5-1) = 12
(4-1) * (2-1) = 3
- When
i=2, a=5
: Check pairs with[2]
(5-1) * (2-1) = 4
- Maximum found: 12
Time Complexity: O(n²)
where n is the length of the array, as we check all possible pairs.
Space Complexity: O(1)
as we only use a constant amount of extra space for the ans
variable.
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 solution with a small example: nums = [2, 5, 3, 7]
Step 1: Initialize
- Set
ans = 0
to track the maximum product
Step 2: First iteration (i=0, a=2)
- Check element 2 against all elements after it: [5, 3, 7]
- Pair (2, 5):
(2-1) * (5-1) = 1 * 4 = 4
- Update:
ans = max(0, 4) = 4
- Update:
- Pair (2, 3):
(2-1) * (3-1) = 1 * 2 = 2
- Update:
ans = max(4, 2) = 4
- Update:
- Pair (2, 7):
(2-1) * (7-1) = 1 * 6 = 6
- Update:
ans = max(4, 6) = 6
- Update:
Step 3: Second iteration (i=1, a=5)
- Check element 5 against all elements after it: [3, 7]
- Pair (5, 3):
(5-1) * (3-1) = 4 * 2 = 8
- Update:
ans = max(6, 8) = 8
- Update:
- Pair (5, 7):
(5-1) * (7-1) = 4 * 6 = 24
- Update:
ans = max(8, 24) = 24
- Update:
Step 4: Third iteration (i=2, a=3)
- Check element 3 against all elements after it: [7]
- Pair (3, 7):
(3-1) * (7-1) = 2 * 6 = 12
- Update:
ans = max(24, 12) = 24
- Update:
Step 5: Return result
- All pairs have been checked
- Return
ans = 24
The maximum product is 24, achieved by selecting the two largest elements (5 and 7) from the array.
Solution Implementation
1class Solution:
2 def maxProduct(self, nums: List[int]) -> int:
3 """
4 Find the maximum product of (nums[i]-1) * (nums[j]-1) for any two distinct indices.
5
6 Args:
7 nums: List of integers
8
9 Returns:
10 Maximum product of (a-1) * (b-1) for any two elements a, b in nums
11 """
12 # Initialize the maximum product to 0
13 max_product = 0
14
15 # Iterate through each element as the first number
16 for i, first_num in enumerate(nums):
17 # Iterate through all elements after index i as the second number
18 for second_num in nums[i + 1:]:
19 # Calculate the product of (first_num - 1) * (second_num - 1)
20 current_product = (first_num - 1) * (second_num - 1)
21
22 # Update maximum product if current product is larger
23 max_product = max(max_product, current_product)
24
25 return max_product
26
1class Solution {
2 /**
3 * Finds the maximum product of (nums[i] - 1) * (nums[j] - 1) for all pairs i < j.
4 *
5 * @param nums the input array of integers
6 * @return the maximum product of any two different elements after subtracting 1 from each
7 */
8 public int maxProduct(int[] nums) {
9 // Initialize the maximum product to 0
10 int maxProductValue = 0;
11
12 // Get the length of the input array
13 int arrayLength = nums.length;
14
15 // Iterate through all pairs of indices where i < j
16 for (int i = 0; i < arrayLength; ++i) {
17 for (int j = i + 1; j < arrayLength; ++j) {
18 // Calculate the product of (nums[i] - 1) and (nums[j] - 1)
19 int currentProduct = (nums[i] - 1) * (nums[j] - 1);
20
21 // Update the maximum product if current product is larger
22 maxProductValue = Math.max(maxProductValue, currentProduct);
23 }
24 }
25
26 // Return the maximum product found
27 return maxProductValue;
28 }
29}
30
1class Solution {
2public:
3 int maxProduct(vector<int>& nums) {
4 // Initialize the maximum product result
5 int maxResult = 0;
6
7 // Get the size of the input array
8 int arraySize = nums.size();
9
10 // Iterate through all pairs of elements
11 for (int i = 0; i < arraySize; ++i) {
12 for (int j = i + 1; j < arraySize; ++j) {
13 // Calculate the product of (nums[i] - 1) * (nums[j] - 1)
14 // and update the maximum result if current product is larger
15 maxResult = max(maxResult, (nums[i] - 1) * (nums[j] - 1));
16 }
17 }
18
19 // Return the maximum product found
20 return maxResult;
21 }
22};
23
1/**
2 * Finds the maximum product of (nums[i] - 1) * (nums[j] - 1) for any two elements in the array
3 * @param nums - Array of positive integers
4 * @returns Maximum product of (nums[i] - 1) * (nums[j] - 1)
5 */
6function maxProduct(nums: number[]): number {
7 const arrayLength: number = nums.length;
8
9 // Perform partial selection sort to find the two largest elements
10 // Only need to sort the first two positions
11 for (let currentPosition = 0; currentPosition < 2; currentPosition++) {
12 let maxElementIndex: number = currentPosition;
13
14 // Find the maximum element from the remaining unsorted portion
15 for (let searchIndex = currentPosition + 1; searchIndex < arrayLength; searchIndex++) {
16 if (nums[searchIndex] > nums[maxElementIndex]) {
17 maxElementIndex = searchIndex;
18 }
19 }
20
21 // Swap the maximum element with the current position
22 [nums[currentPosition], nums[maxElementIndex]] = [nums[maxElementIndex], nums[currentPosition]];
23 }
24
25 // Calculate and return the product of (first largest - 1) * (second largest - 1)
26 return (nums[0] - 1) * (nums[1] - 1);
27}
28
Time and Space Complexity
Time Complexity: O(n²)
The code uses two nested loops to iterate through all pairs of elements in the array. The outer loop runs n
times (where n
is the length of the array), and for each iteration i
, the inner loop runs (n - i - 1)
times. This gives us a total of:
(n-1) + (n-2) + ... + 1 = n(n-1)/2
iterations
Therefore, the time complexity is O(n²)
.
Space Complexity: O(1)
The algorithm only uses a constant amount of extra space:
- Variable
ans
to store the maximum product - Loop variables
i
,a
, andb
No additional data structures are created that scale with the input size, so the space complexity is O(1)
.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Inefficient O(n²) Solution When O(n) is Possible
The brute force approach checks all possible pairs, resulting in O(n²) time complexity. However, this problem can be solved in O(n) time by recognizing that to maximize (a-1) * (b-1)
, we simply need to find the two largest numbers in the array.
Why this works: Since we're subtracting 1 from both numbers before multiplying, the product is maximized when both (a-1)
and (b-1)
are as large as possible, which happens when a
and b
are the two largest values in the array.
Optimized O(n) Solution:
class Solution:
def maxProduct(self, nums: List[int]) -> int:
# Find the two largest numbers in a single pass
first_max = second_max = 0
for num in nums:
if num > first_max:
second_max = first_max
first_max = num
elif num > second_max:
second_max = num
return (first_max - 1) * (second_max - 1)
2. Not Handling Edge Cases with Negative Numbers
If the problem allowed negative numbers in the array, the current approach might miss the optimal solution. For example, with [-5, -4, 3, 2]
, the maximum product would be (-5-1) * (-4-1) = (-6) * (-5) = 30
, not (3-1) * (2-1) = 2
.
Solution: If negative numbers are possible, you'd need to track both the two largest and two smallest values:
class Solution:
def maxProduct(self, nums: List[int]) -> int:
# Track both largest and smallest values
nums.sort()
# Compare product of two smallest vs two largest
return max(
(nums[0] - 1) * (nums[1] - 1), # Two smallest (could be negative)
(nums[-1] - 1) * (nums[-2] - 1) # Two largest
)
3. Unnecessary Memory Usage with Slicing
The current solution uses nums[i + 1:]
which creates a new list slice for each iteration. While this doesn't affect the overall space complexity (still O(1)), it creates unnecessary temporary objects.
Better approach using indices:
class Solution:
def maxProduct(self, nums: List[int]) -> int:
max_product = 0
n = len(nums)
for i in range(n):
for j in range(i + 1, n):
current_product = (nums[i] - 1) * (nums[j] - 1)
max_product = max(max_product, current_product)
return max_product
Problem: Given a list of tasks and a list of requirements, compute a sequence of tasks that can be performed, such that we complete every task once while satisfying all the requirements.
Which of the following method should we use to solve this problem?
Recommended Readings
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
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
Want a Structured Path to Master System Design Too? Don’t Miss This!