
Problem Statement
Given two integer arrays, nums1 and nums2, the objective is to find the maximum possible dot product between non-empty subsequences of these two arrays that have the same length. A subsequence is a sequence that can be derived from an array by removing some or no elements without changing the order of the remaining elements. The dot product of two sequences of equal length is obtained by multiplying corresponding elements and summing up the results. This problem requires optimizing the choice of subsequences such that their dot product is maximized.
Examples
Example 1
Input:
nums1 = [2,1,-2,5], nums2 = [3,0,-6]
Output:
18
Explanation:
Take subsequence [2,-2] from nums1 and subsequence [3,-6] from nums2. Their dot product is (2*3 + (-2)*(-6)) = 18.
Example 2
Input:
nums1 = [3,-2], nums2 = [2,-6,7]
Output:
21
Explanation:
Take subsequence [3] from nums1 and subsequence [7] from nums2. Their dot product is (3*7) = 21.
Example 3
Input:
nums1 = [-1,-1], nums2 = [1,1]
Output:
-1
Explanation:
Take subsequence [-1] from nums1 and subsequence [1] from nums2. Their dot product is -1.
Constraints
1 <= nums1.length, nums2.length <= 500-1000 <= nums1[i], nums2[i] <= 1000
Approach and Intuition
To derive the solution for the maximum dot product between subsequences of two arrays, we rely on dynamic programming due to the combinatorial nature of subsequences and the optimization criteria.
Understanding Subsequences and Dot Products:
- Subsequences are derived by skipping some elements in the original arrays without reordering the remaining elements.
- The dot product of two vectors (or sequences)
AandBof the same lengthnis calculated as:sum(A[i] * B[i] for i in range(n)).
Dynamic Programming Array:
- We can use a 2D dynamic programming array
dpwheredp[i][j]represents the maximum dot product of subsequences taken from the firstielements ofnums1and the firstjelements ofnums2.
- We can use a 2D dynamic programming array
Recursive Relation:
- Initialize the
dparray with a minimal value since we are looking for the maximum product. - For each pair of indices
(i, j), we consider:- Not including either
nums1[i-1]ornums2[j-1]in the subsequences:dp[i-1][j]anddp[i][j-1]. - Including both
nums1[i-1]andnums2[j-1], and thus the productnums1[i-1] * nums2[j-1]and the best result from previous indicesdp[i-1][j-1].
- Not including either
- Initialize the
Transition Formula:
dp[i][j] = max(dp[i][j], dp[i-1][j], dp[i][j-1], dp[i-1][j-1] + nums1[i-1]*nums2[j-1])This relation consolidates all possibilities by comparing existing values in thedpmatrix and updating it with potential new maximums.
Initialization:
- Since we're dealing with subsequences and not subarrays, each
dp[i][0]anddp[0][j](whereiandjstart from 1) should be initiated considering the empty subsequence scenario for eithernums1ornums2.
- Since we're dealing with subsequences and not subarrays, each
Result:
- The value at
dp[length of nums1][length of nums2]gives the maximum dot product of any non-empty subsequence betweennums1andnums2.
- The value at
This approach leverages the flexibility of dynamic programming to address complexities that arise from multiple choices and the requirement of correlations between decisions. By caching results that reflect the best decisions up to that point, we ensure that our final decision at dp[n][m] (where n and m are the lengths of nums1 and nums2, respectively) yields the optimal solution.
Solutions
- C++
- Java
- Python
class Solution {
public:
int maxDotProduct(vector<int>& arr1, vector<int>& arr2) {
int max1 = INT_MIN, max2 = INT_MIN;
int min1 = INT_MAX, min2 = INT_MAX;
for (int element : arr1) {
max1 = max(max1, element);
min1 = min(min1, element);
}
for (int element : arr2) {
max2 = max(max2, element);
min2 = min(min2, element);
}
if (max1 < 0 && min2 > 0) {
return max1 * min2;
}
if (min1 > 0 && max2 < 0) {
return min1 * max2;
}
int length = arr2.size() + 1;
vector<int> current(length, 0);
vector<int> prev(length, 0);
for (int i = arr1.size() - 1; i >= 0; i--) {
current = vector<int>(length, 0);
for (int j = arr2.size() - 1; j >= 0; j--) {
int productSum = arr1[i] * arr2[j] + prev[j + 1];
current[j] = max(productSum, max(prev[j], current[j + 1]));
}
prev = current;
}
return current[0];
}
};
To solve the problem of finding the maximum dot product of two subsequences using C++, the provided solution performs the following:
Initialize Variables: Establish variables for tracking the maximum and minimum values of the two arrays. These help in determining edge cases where all elements in one array are negative and all in the other are positive or vice versa.
Check for Edge Cases:
- If the maximum value in the first array is negative and the minimum value in the second array is positive, the result is the product of these two values.
- If the minimum value in the first array is positive and the maximum value in the second array is negative, then the result is the product of these values.
Dynamic Programming Approach:
- Use two vectors,
currentandprev, initialized to the size of the second array plus one. These vectors store the results of subproblems, enabling an efficient build-up to the final solution. - Iterate backwards through both arrays, calculating potential dot products for every subsequence pair. Update the
currentvector based on the maximum of:- The dot product of the current elements from both arrays plus the result of the best subsequence excluding the current elements.
- The best result excluding the current element from the second array.
- The result from processing previous elements.
- After processing each element from the first array, copy the
currentvector toprevto prepare for the next iteration.
- Use two vectors,
Return the Result: The first element of the
currentvector after processing all elements contains the maximum dot product of two subsequences.
Through this approach, you efficiently address both the direct computation and the rule-based scenarios using conditional logic and dynamic programming.
class Solution {
public int maximumDotProduct(int[] array1, int[] array2) {
int topMax = Integer.MIN_VALUE;
int nextMax = Integer.MIN_VALUE;
int topMin = Integer.MAX_VALUE;
int nextMin = Integer.MAX_VALUE;
for (int val: array1) {
topMax = Math.max(topMax, val);
topMin = Math.min(topMin, val);
}
for (int val: array2) {
nextMax = Math.max(nextMax, val);
nextMin = Math.min(nextMin, val);
}
if (topMax < 0 && nextMin > 0) {
return topMax * nextMin;
}
if (topMin > 0 && nextMax < 0) {
return topMin * nextMax;
}
int n = array2.length + 1;
int[] currentDp = new int[n];
int[] previousDp = new int[n];
for (int i = array1.length - 1; i >= 0; i--) {
currentDp = new int[n];
for (int j = array2.length - 1; j >= 0; j--) {
int choose = array1[i] * array2[j] + previousDp[j + 1];
currentDp[j] = Math.max(choose, Math.max(previousDp[j], currentDp[j + 1]));
}
previousDp = currentDp;
}
return currentDp[0];
}
}
The provided Java solution calculates the maximum dot product of two subsequences from given integer arrays. The maximumDotProduct function efficiently finds this value through dynamic programming and straightforward logic checks. The following summarizes the method and logic:
- First, identify the maximum (
topMax) and minimum (topMin) values inarray1, and the maximum (nextMax) and minimum (nextMin) values inarray2using for-loops. - Handle specific cases where the maximum or minimum values across the arrays are only positive or negative. These cases optimize scenarios where multiplying the smallest and largest negative and positive integers respectively might render the maximum dot product:
- If
topMaxis negative andnextMinis positive, return the multiplication oftopMax*nextMin. - If
topMinis positive andnextMaxis negative, return the multiplication oftopMin*nextMax.
- If
- Use a dynamic programming approach to handle the general case:
- Initialize two arrays,
currentDpandpreviousDp, to track states.currentDpcorresponds to potential max dot products at the current iteration, andpreviousDpto the previous iteration. - Traverse the arrays
array1andarray2in reverse to consider all possible subsequences. Calculate potential dot products by deciding whether to include or exclude current elements fromarray1andarray2. - The final result, representing the maximum dot product of two subsequences, is stored in
currentDp[0].
- Initialize two arrays,
By following this procedure, the program ensures optimal and efficient computation of the maximum dot product between two subsequences of the provided integer arrays. This method leverages both simple condition checks and a more complex dynamic programming technique, making it adaptable to various input conditions.
class Solution:
def maximumDotProduct(self, list1: List[int], list2: List[int]) -> int:
if max(list1) < 0 and min(list2) > 0:
return max(list1) * min(list2)
if min(list1) > 0 and max(list2) < 0:
return min(list1) * max(list2)
len_list2 = len(list2) + 1
previous = [0] * len_list2
current = [0] * len_list2
for i in range(len(list1) - 1, -1, -1):
current = [0] * len_list2
for j in range(len(list2) - 1, -1, -1):
choice1 = list1[i] * list2[j] + previous[j + 1]
current[j] = max(choice1, previous[j], current[j + 1])
previous = current
return current[0]
The given solution calculates the maximum dot product between any subsequence of two lists of integers, list1 and list2, using dynamic programming in Python. Here's a breakdown of how the function implemented in the Solution class works to achieve this:
- First, the function checks if all elements in
list1are negative and all elements inlist2are positive or vice versa. If this condition is met, then the maximum dot product is simply the product of the maximum value in the smaller list with the minimum value in the larger list. - The solution initializes two lists,
previousandcurrent, both filled with zeros and sized based on the length oflist2plus one. These lists are used to store intermediate results and update values for each iteration. - A nested loop iterates backward through each element in
list1andlist2. For each pair of elements, the function computes the possible dot product values:choice1handles the case where both elements fromlist1andlist2are included in the subsequences being considered.- The values in the
currentarray are updated based on the maximum ofchoice1, keeping the previous value inlist1(previous[j]), or excluding the current element inlist2(current[j + 1]).
- After iterating through all elements,
previousis updated with the values ofcurrentto carry forward the computation to the next element oflist1. - Once all iterations are complete,
current[0]contains the maximum dot product of two subsequences fromlist1andlist2.
This approach efficiently finds the maximum dot product by utilizing dynamic programming to avoid redundant calculations, thus optimizing performance for larger lists.