1464. Maximum Product of Two Elements in an Array
Problem Description
In this LeetCode problem, we are given an array of integers called nums
. Our goal is to select two different indices i
and j
within this array. We are then asked to calculate the product of the values at these indices, decreased by 1. Specifically, we need to find (nums[i] - 1) * (nums[j] - 1)
that results in the maximum possible value. To clarify, since i
and j
must be different, the elements nums[i]
and nums[j]
must be distinct elements—even if they have the same value.
Intuition
The key intuition here is that in order to maximize the product (nums[i] - 1) * (nums[j] - 1)
, we need to identify the two largest numbers in the array nums
. This is because the product of any other pair would be less than or equal to the product of the two largest numbers.
The thought process starts with initializing two variables, which will hold the two largest numbers found while iterating through the array. As we go through each number in the array:
- If we find a number greater than the largest number we've found so far (
a
), then we shift the previous largest number to be the second-largest (b
) and update the largest number (a
) with the new number. - If the current number is not larger than
a
but is larger thanb
, we just update the second-largest number (b
).
Once we have the two largest numbers, we subtract 1 from each (as per the problem statement) and return their product. By following this approach, we do not need to worry about which indices we chose; we only need the values to compute the desired maximum product.
Learn more about Sorting and Heap (Priority Queue) patterns.
Solution Approach
The solution uses a straightforward linear scan algorithm to iterate through the array of numbers. We use two variables, a
and b
, to keep track of the largest and second-largest numbers in the array, respectively. There's no need for any additional data structure as we only need to maintain these two variables through the iteration.
Here's a step-by-step walkthrough of the implementation:
-
Initialize two variables,
a
andb
, both set to 0. These will be used to track the largest (a
) and second largest (b
) numbers in the array. -
Loop through each value
v
in the arraynums
. -
Check if the current value
v
is greater than our current largest valuea
.- If
v
is larger thana
, then we need to update botha
andb
. Setb
to the old value ofa
(becausea
is going to be replaced with a larger value, and thus the previousa
becomes the second-largest), anda
tov
.
- If
-
If
v
is not larger thana
but is larger thanb
, then just updateb
to bev
, because we found a new second-largest number. -
Once the loop is over, we have identified the two largest values in the array. We calculate the result as
(a - 1) * (b - 1)
and return it. -
Return the computed product as the solution.
In terms of complexity:
- Time Complexity is
O(n)
because we go through the array of numbers exactly once. - Space Complexity is
O(1)
as we are using a fixed amount of space regardless of the input array size.
The elegance of this approach lies in its simplicity and efficiency, as there is no need for sorting or additional data structures like heaps or trees, which would increase the complexity of the solution.
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Consider an example array nums
given as [3, 4, 5, 2]
.
Following the solution approach:
-
Initialize two variables
a
andb
to0
. So initially,a = 0
andb = 0
. -
Loop through each value
v
in the arraynums
. -
Start with the first value
3
:- Is
3
greater thana
(which is0
)? Yes. - Update
b
to the currenta
, so nowb = 0
. - Update
a
to the current valuev
, nowa = 3
.
- Is
-
Move to the second value
4
:- Is
4
greater thana
(which is3
)? Yes. - Update
b
to the currenta
, so nowb = 3
. - Update
a
to the current valuev
, nowa = 4
.
- Is
-
Now, look at the third value
5
:- Is
5
greater thana
(which is4
)? Yes. - Update
b
to the currenta
, sob = 4
. - Update
a
to5
, the current valuev
.
- Is
-
Finally, consider the last value
2
:- Is
2
greater thana
(which is5
)? No. - Is
2
greater thanb
(which is4
)? No. - So no updates to
a
orb
occur because2
is neither the largest nor the second-largest number found so far.
- Is
-
After the loop, our two largest values have been found:
a = 5
andb = 4
. -
Calculate the result as
(a - 1) * (b - 1)
, which is(5 - 1) * (4 - 1) = 4 * 3 = 12
. -
Return the product
12
as the solution.
In this example, the selected values are 5
(at index 2
) and 4
(at index 1
). Subtracting 1
from each and then multiplying, we get the maximum possible product value 12
as the output for this input array.
Solution Implementation
1from typing import List
2
3class Solution:
4 def maxProduct(self, nums: List[int]) -> int:
5 # Initialize the two largest numbers as 0
6 max_num1 = max_num2 = 0
7
8 # Loop through each number in the list
9 for value in nums:
10 # If the current value is greater than the first maximum number
11 if value > max_num1:
12 # Update the first and second maximum numbers
13 max_num1, max_num2 = value, max_num1
14 # Else if the current value is only greater than the second maximum number
15 elif value > max_num2:
16 # Update the second maximum number
17 max_num2 = value
18
19 # Return the product of the two highest numbers after subtracting 1 from each
20 return (max_num1 - 1) * (max_num2 - 1)
21
1class Solution {
2 public int maxProduct(int[] nums) {
3 // Initialize two variables to store the largest and second largest values
4 // We start with the smallest possible values for integers
5 int maxVal = Integer.MIN_VALUE;
6 int secondMaxVal = Integer.MIN_VALUE;
7
8 // Iterate through each value in the nums array
9 for (int value : nums) {
10 // Check if the current value is greater than the largest value found so far
11 if (value > maxVal) {
12 // If it is, the current largest becomes the second largest,
13 // and the current value becomes the new largest
14 secondMaxVal = maxVal;
15 maxVal = value;
16 } else if (value > secondMaxVal) {
17 // If the current value is not larger than the largest but is larger
18 // than the second largest, update the second largest
19 secondMaxVal = value;
20 }
21 }
22
23 // Return the product of the largest and second largest values decreased by 1
24 // This is because the problem statement likely intended for a pair of values
25 // whose product is maximized after each is decreased by 1
26 return (maxVal - 1) * (secondMaxVal - 1);
27 }
28}
29
1#include <vector> // Include the necessary header for vector
2
3class Solution {
4public:
5 // Function to calculate the maximum product of (the max number - 1) and (the second max number - 1) in a vector
6 int maxProduct(vector<int>& nums) {
7 int maxNum = 0; // Initialize the maximum number to 0
8 int secondMaxNum = 0; // Initialize the second maximum number to 0
9
10 // Iterate through each number in the vector
11 for (int value : nums) {
12 // If current value is greater than the maximum number found so far
13 if (value > maxNum) {
14 secondMaxNum = maxNum; // Assign the old maximum to be the second maximum
15 maxNum = value; // Update the maximum number to the current value
16 }
17 // Else if current value is not greater than maxNum but greater than secondMaxNum
18 else if (value > secondMaxNum) {
19 secondMaxNum = value; // Update the second maximum number to the current value
20 }
21 }
22
23 // Calculate and return the product of (maxNum - 1) and (secondMaxNum - 1)
24 return (maxNum - 1) * (secondMaxNum - 1);
25 }
26};
27
1/**
2 * Finds the maximum product of (num1 - 1) * (num2 - 1) where num1 and num2
3 * are the two largest numbers in the array.
4 * @param nums Array of numbers.
5 * @returns The maximum product.
6 */
7function maxProduct(nums: number[]): number {
8 let firstMax = 0; // Holds the largest number found in the array
9 let secondMax = 0; // Holds the second largest number found in the array
10
11 // Iterate through each number in the provided array
12 for (const num of nums) {
13 if (num > firstMax) {
14 // If the current number is greater than firstMax, update secondMax to firstMax
15 // and then update firstMax to the current number
16 secondMax = firstMax;
17 firstMax = num;
18 } else if (num > secondMax) {
19 // If the current number is not greater than firstMax but is greater than secondMax,
20 // update secondMax to the current number
21 secondMax = num;
22 }
23 }
24
25 // Return the product of (firstMax - 1) and (secondMax - 1)
26 return (firstMax - 1) * (secondMax - 1);
27}
28
Time and Space Complexity
The time complexity of the given code is O(n)
, where n
is the length of the input array nums
. This is because the code includes a single for-loop that iterates over all elements in the array once to find the two largest elements.
The space complexity of the solution is O(1)
. This is constant space because the solution only uses a fixed amount of extra space to store the largest (a
) and the second-largest (b
) values in the array, regardless of the input size.
Learn more about how to find time and space complexity quickly using problem constraints.
What's the output of running the following function using the following tree as input?
1def serialize(root):
2 res = []
3 def dfs(root):
4 if not root:
5 res.append('x')
6 return
7 res.append(root.val)
8 dfs(root.left)
9 dfs(root.right)
10 dfs(root)
11 return ' '.join(res)
12
1import java.util.StringJoiner;
2
3public static String serialize(Node root) {
4 StringJoiner res = new StringJoiner(" ");
5 serializeDFS(root, res);
6 return res.toString();
7}
8
9private static void serializeDFS(Node root, StringJoiner result) {
10 if (root == null) {
11 result.add("x");
12 return;
13 }
14 result.add(Integer.toString(root.val));
15 serializeDFS(root.left, result);
16 serializeDFS(root.right, result);
17}
18
1function serialize(root) {
2 let res = [];
3 serialize_dfs(root, res);
4 return res.join(" ");
5}
6
7function serialize_dfs(root, res) {
8 if (!root) {
9 res.push("x");
10 return;
11 }
12 res.push(root.val);
13 serialize_dfs(root.left, res);
14 serialize_dfs(root.right, res);
15}
16
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 algomonster s3 us east 2 amazonaws com 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
LeetCode 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 we
Want a Structured Path to Master System Design Too? Don’t Miss This!