Skip to content

Latest commit

 

History

History

1458

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 

Given two arrays nums1 and nums2.

Return the maximum dot product between non-empty subsequences of nums1 and nums2 with the same length.

A subsequence of a array is a new array which is formed from the original array by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (ie, [2,3,5] is a subsequence of [1,2,3,4,5] while [1,5,3] is not).

 

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

Companies: Microsoft

Related Topics:
Array, Dynamic Programming

Hints:

  • Use dynamic programming, define DP[i][j] as the maximum dot product of two subsequences starting in the position i of nums1 and position j of nums2.

Solution 1. DP

Let dp[i + 1][j + 1] be the answer to the subproblem on A[0..i] and B[0..j].

For dp[0][i] and dp[i][0], they mean that either A or B is empty array. Since the question is asking for non-empty subsequences, they are not valid cases, so we should regard them as -INF.

For dp[i + 1][j + 1], we have three choices:

  • We include A[i] and B[j] in the subsequences. We get max(0, dp[i][j]) + A[i] * B[j].
  • We ignore A[i] and reuse the result of dp[i][j + 1].
  • We ignore B[j] and reuse the result of dp[i + 1][j].
// For 0 <= i < M, 0 <= j < N
dp[i + 1][j + 1] = max(
                        max(0, dp[i][j]) + A[i] * B[j],   // If we include A[i] and B[j] in the subsequences
                        dp[i][j + 1],                     // If we don't include A[i] in the subsequence
                        dp[i + 1][j]                      // If we don't include B[j] in the subsequence
                      )

// For 0 <= j <= N, 0 <= i <= M
dp[0][j] = dp[i][0] = -INF
// OJ: https://leetcode.com/problems/max-dot-product-of-two-subsequences/
// Author: github.com/lzl124631x
// Time: O(MN)
// Space: O(MN)
class Solution {
public:
    int maxDotProduct(vector<int>& A, vector<int>& B) {
        int M = A.size(), N = B.size();
        vector<vector<int>> dp(M + 1, vector<int>(N + 1, INT_MIN));
        for (int i = 0; i < M; ++i) {
            for (int j = 0; j < N; ++j) {
                dp[i + 1][j + 1] = max({ max(0, dp[i][j]) + A[i] * B[j], dp[i + 1][j], dp[i][j + 1] });
            }
        }
        return dp[M][N];
    }
};

Solution 2. DP with Space Optimization

Since dp[i + 1][j + 1] only depends on dp[i][j], dp[i + 1][j] and dp[i][j + 1], we can reduce the size of the dp array from M * N to 2 * N.

// OJ: https://leetcode.com/problems/max-dot-product-of-two-subsequences
// Author: github.com/lzl124631x
// Time: O(MN)
// Space: O(min(M, N))
class Solution {
public:
    int maxDotProduct(vector<int>& A, vector<int>& B) {
        int M = A.size(), N = B.size();
        if (N > M) swap(A, B), swap(M, N);
        vector<int> dp(N + 1, INT_MIN);
        for (int i = 0; i < M; ++i) {
            vector<int> next(N + 1, INT_MIN);
            for (int j = 0; j < N; ++j) {
                next[j + 1] = max({A[i] * B[j] + max(0, dp[j]), dp[j + 1], next[j]});
            }
            swap(dp, next);
        }
        return dp[N];
    }
};

Or further reduce the space to 1 * N.

// OJ: https://leetcode.com/problems/max-dot-product-of-two-subsequences/
// Author: github.com/lzl124631x
// Time: O(MN)
// Space: O(min(M, N))
class Solution {
public:
    int maxDotProduct(vector<int>& A, vector<int>& B) {
        int M = A.size(), N = B.size();
        if (N > M) swap(A, B), swap(M, N);
        vector<int> dp(N + 1, INT_MIN);
        for (int i = 0; i < M; ++i) {
            int prev = INT_MIN;
            for (int j = 0; j < N; ++j) {
                int cur = dp[j + 1];
                dp[j + 1] = max({A[i] * B[j] + max(0, prev), dp[j + 1], dp[j]});
                prev = cur;
            }
        }
        return dp[N];
    }
};