Maximum Multiplication Score
MedPrompt
You are given an integer array a of size 4 and another integer array b of size at least 4.
You need to choose 4 indices i0, i1, i2, and i3 from the array b such that i0 < i1 < i2 < i3. Your score will be equal to the value a[0] * b[i0] + a[1] * b[i1] + a[2] * b[i2] + a[3] * b[i3].
Return the maximum score you can achieve.
Example 1:
Input: a = [3,2,5,6], b = [2,-6,4,-5,-3,2,-7]
Output: 26
Explanation:
We can choose the indices 0, 1, 2, and 5. The score will be 3 * 2 + 2 * (-6) + 5 * 4 + 6 * 2 = 26.
Example 2:
Input: a = [-1,4,5,-2], b = [-5,-1,-3,-2,-4]
Output: -1
Explanation:
We can choose the indices 0, 1, 3, and 4. The score will be (-1) * (-5) + 4 * (-1) + 5 * (-2) + (-2) * (-4) = -1.
Constraints:
a.length == 44 <= b.length <= 105-105 <= a[i], b[i] <= 105
Approaches
3 approaches with complexity analysis and trade-offs.
A more efficient solution uses dynamic programming. The problem has optimal substructure and overlapping subproblems. We can build the solution iteratively. We first find the maximum scores possible by choosing one element, then use those results to find the maximum scores for choosing two elements, and so on, up to four elements.
Algorithm
- Define
dp[k][i]as the maximum score using the firstkelements ofaandkelements chosen from the prefixb[0...i]. - The state transition is
dp[k][i] = max(dp[k][i-1], dp[k-1][i-1] + a[k-1] * b[i]). dp[k][i-1]corresponds to not pickingb[i].dp[k-1][i-1] + a[k-1] * b[i]corresponds to pickingb[i]as the k-th element.- Since
dp[k]only depends ondp[k-1], we can optimize space from O(k*N) to O(N) by using two arrays:prev_dpfor stagek-1andcurr_dpfor stagek. - Initialize a
dparray of sizenfor thek=1case. - Iterate
kfrom 2 to 4, calculating thedpvalues for the current stage using the values from the previous stage. - The final answer is the last element of the
dparray after computing fork=4.
Walkthrough
Let's define dp[k][i] as the maximum score using a[0]...a[k-1] and k elements from b chosen from the prefix b[0...i]. The recurrence relation captures the two choices at each step i for each number of elements k: either we include b[i] as the k-th element or we don't.
dp[k][i] = max(dp[k][i-1], dp[k-1][i-1] + (long)a[k-1] * b[i])
This would typically require a 2D DP table of size 4 x N. However, we can observe that to compute the values for k elements, we only need the results for k-1 elements. This allows for a space optimization where we only need to store the DP results for the previous k and the current k, reducing space to O(N).
class Solution { public long maximumMultiplicationScore(int[] a, int[] b) { int n = b.length; long[] dp = new long[n]; // k = 1 dp[0] = (long) a[0] * b[0]; for (int i = 1; i < n; i++) { dp[i] = Math.max(dp[i - 1], (long) a[0] * b[i]); } // k = 2 to 4 for (int k = 1; k < 4; k++) { long[] prev_dp = dp; dp = new long[n]; // We need at least k elements (0-indexed) // so the first possible score is at index k. // dp[k] = prev_dp[k-1] + a[k]*b[k] // Initialize dp[k-1] to a very small value to handle the max correctly. dp[k-1] = Long.MIN_VALUE; for (int i = k; i < n; i++) { long pick_b_i = prev_dp[i - 1] + (long) a[k] * b[i]; long not_pick_b_i = dp[i - 1]; dp[i] = Math.max(pick_b_i, not_pick_b_i); } } return dp[n - 1]; }}Complexity
Time
O(k * N) - Where `k=4` and N is the length of `b`. Since `k` is a constant, the complexity is linear, O(N).
Space
O(N) - We use an array of size N to store the DP states for each of the 4 stages. With the optimization, we use two arrays of size N, which is still O(N).
Trade-offs
Pros
Efficient linear time complexity, which passes the given constraints.
Conceptually builds upon a standard DP pattern.
Cons
Requires linear space, which could be a limitation if memory is highly constrained, though it's acceptable for this problem's constraints.
The brute-force approach is the most intuitive way to solve the problem. It involves generating every possible valid combination of four indices from the array b and calculating the score for each combination. By keeping track of the highest score seen so far, we can find the maximum possible score.
Algorithm
- Initialize a variable
maxScoreto a very small number (e.g.,Long.MIN_VALUE). - Let
nbe the length of arrayb. - Use a set of four nested loops to iterate through all possible combinations of indices
i0,i1,i2,i3such that0 <= i0 < i1 < i2 < i3 < n. - The first loop runs for
i0from0ton - 4. - The second loop runs for
i1fromi0 + 1ton - 3. - The third loop runs for
i2fromi1 + 1ton - 2. - The fourth loop runs for
i3fromi2 + 1ton - 1. - Inside the innermost loop, calculate the score:
score = a[0] * b[i0] + a[1] * b[i1] + a[2] * b[i2] + a[3] * b[i3]. - Update
maxScore = Math.max(maxScore, score). - After the loops complete, return
maxScore.
Walkthrough
This method systematically checks every single valid quadruplet of indices (i0, i1, i2, i3) where the indices are in increasing order. Four nested loops are a natural way to implement this. The outer loop selects the first index i0, the next loop selects i1 ensuring it's greater than i0, and so on. For each valid set of four indices, we compute the multiplication score and compare it with our current maximum, updating it if the new score is higher. While simple, this exhaustive search is computationally very expensive.
class Solution { public long maximumMultiplicationScore(int[] a, int[] b) { long maxScore = Long.MIN_VALUE; int n = b.length; for (int i0 = 0; i0 < n; i0++) { for (int i1 = i0 + 1; i1 < n; i1++) { for (int i2 = i1 + 1; i2 < n; i2++) { for (int i3 = i2 + 1; i3 < n; i3++) { long currentScore = (long) a[0] * b[i0] + (long) a[1] * b[i1] + (long) a[2] * b[i2] + (long) a[3] * b[i3]; if (currentScore > maxScore) { maxScore = currentScore; } } } } } return maxScore; }}Complexity
Time
O(N^4) - Where N is the length of array `b`. The four nested loops result in a quartic time complexity, making it infeasible for N up to 10^5.
Space
O(1) - Constant extra space is used, as we only need a few variables to store the loop indices and the maximum score.
Trade-offs
Pros
Simple to understand and straightforward to implement.
Correct for small input sizes.
Cons
Extremely inefficient due to its O(N^4) time complexity.
Will result in a 'Time Limit Exceeded' (TLE) error for the given constraints on the size of array
b.
The most optimal solution builds upon the dynamic programming approach but reduces the space complexity to constant. By cleverly ordering the loops and state updates, we can eliminate the need for O(N) space, using only a small, constant-size array to store the DP states.
Algorithm
- Create a
longarraydpof size 5. - Initialize
dp[0] = 0anddp[1]throughdp[4]to a very small number likeLong.MIN_VALUE. dp[k]will store the maximum score usingkelements fromaandkelements frombfrom the prefix processed so far.- Iterate through each element
valin the arrayb. - For each
val, iterate backwards fromk = 4down to1. - Inside the inner loop, update
dp[k]using the formula:dp[k] = max(dp[k], dp[k-1] + (long)a[k-1] * val). - The backward iteration is crucial. It ensures that when
dp[k]is updated,dp[k-1]holds the value from before processing the currentval, thus satisfying thei0 < i1 < ...constraint. - After iterating through all elements of
b,dp[4]will hold the maximum possible score.
Walkthrough
This approach refines the DP solution to use O(1) space. We maintain a single array dp of size 5, where dp[k] represents the maximum score for choosing k elements. We iterate through each number in b. For each number, we update our dp array. The key is to iterate k from 4 down to 1. This ensures that when we compute the new value for dp[k], the value of dp[k-1] we use is the one from before processing the current number from b, which is exactly what we need. This is a common space-optimization technique for DP problems similar to the 0/1 knapsack problem.
class Solution { public long maximumMultiplicationScore(int[] a, int[] b) { int n = b.length; // dp[k] = max score using k elements long[] dp = new long[5]; // Initialize with a very small value for (int i = 1; i <= 4; i++) { dp[i] = Long.MIN_VALUE; } // dp[0] = 0 is the base case: score with 0 elements is 0. for (int val : b) { // Iterate k backwards to use dp[k-1] from the previous state (before this val) for (int k = 4; k >= 1; k--) { // We can only form a score of k items if a score of k-1 items was possible. if (dp[k - 1] != Long.MIN_VALUE) { dp[k] = Math.max(dp[k], dp[k - 1] + (long) a[k - 1] * val); } } } return dp[4]; }}Complexity
Time
O(k * N) - Where `k=4` and N is the length of `b`. The two nested loops give a linear time complexity of O(N).
Space
O(1) - The space required is for the `dp` array of size 5, which is constant and does not depend on the input size N.
Trade-offs
Pros
Most efficient solution with linear time and constant space.
Optimal in terms of both time and space complexity.
Cons
The logic, especially the backward iteration for
k, can be less intuitive to understand initially compared to the O(N) space version.
Solutions
Solution
class Solution {private Long[][] f;private int[] a;private int[] b;public long maxScore(int[] a, int[] b) { f = new Long[a.length][b.length]; this.a = a; this.b = b; return dfs(0, 0); }private long dfs(int i, int j) { if (j >= b.length) { return i >= a.length ? 0 : Long.MIN_VALUE / 2; } if (i >= a.length) { return 0; } if (f[i][j] != null) { return f[i][j]; } return f[i][j] = Math.max(dfs(i, j + 1), 1L * a[i] * b[j] + dfs(i + 1, j + 1)); }}class Solution {public: long long maxScore(vector<int> &a, vector<int> &b) { int m = a.size(), n = b.size(); long long f[m][n]; memset(f, -1, sizeof(f)); auto dfs = [&](auto &&dfs, int i, int j) -> long long { if (j >= n) { return i >= m ? 0 : LLONG_MIN / 2; } if (i >= m) { return 0; } if (f[i][j] != -1) { return f[i][j]; } return f[i][j] = max(dfs(dfs, i, j + 1), 1LL * a[i] * b[j] + dfs(dfs, i + 1, j + 1)); }; return dfs(dfs, 0, 0); }};class Solution: def maxScore(self, a: List[int], b: List[int]) -> int: @ cache def dfs(i: int, j: int) -> int: if j >= len(b): return 0 if i >= len(a) else - inf if i >= len(a): return 0 return max(dfs(i, j + 1), a[i] * b[j] + dfs(i + 1, j + 1)) return dfs(0, 0)Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.