AKSHAY
AKSHAY

Reputation: 23

Maximum Score from Performing Multiplication Operations

You are given two integer arrays nums and multipliers of size n and m respectively, where n >= m. The arrays are 1-indexed.

You begin with a score of 0. You want to perform exactly m operations. On the ith operation (1-indexed), you will:

Constraints: 1.Choose one integer x from either the start or the end of the array nums.

2.Add multipliers[i] * x to your score.

3.Remove x from the array nums.

Return the maximum score after performing m operations.

for example : nums = [-5,-3,-3,-2,7,1] and multipliers = [-10,-5,3,4,6]

Output : 102

public int maximumScore(int[] nums, int[] multipliers) {
    int totalValue = 0;
    int length = multipliers.length;
    int start = 0;
    for(int i =0,j=nums.length-1;i<=j && length!=0;){
        int max = 0;
        if(nums[i] * multipliers[start] > nums[j]*multipliers[start]){
            max = nums[i] * multipliers[start];
            i++;
        }else{
            max = nums[j]*multipliers[start];
            j--;
        }
        start++;
        totalValue+=max;
        
        length--;
    }
    
    return totalValue;
}

My code but sadly doesnt work and prints output as 120 .. Any solution with explanation would be helpful thanks.

Upvotes: 0

Views: 692

Answers (2)

dikshant gupta
dikshant gupta

Reputation: 1

The problem can be solved using recursion and then optimized for overlapping subproblems using dynamic programming. A simple recursive solution would look like this (in C++):

int solver(int i, vector<int>& n, vector<int>& m, int s, int e) {
    if(i == size(m)) return 0;
    return max(m[i] * n[s] + solver(i + 1, n, m, s + 1, e), m[i] * n[e] + solver(i + 1, n, m, s, e - 1));
    return dp[i][s];
  }

int maximumScore(vector<int>& nums, vector<int>& multipliers) {
    int score = solver(0, nums, multipliers, 0, nums.size() - 1);
    return score;
}

This can be further optimized by storing the results in an array and using them rather than computing the same problem again.

class Solution {
public:
    int dp[1001][1001];
    int solver(int i, vector<int>& n, vector<int>& m, int s) {
        if(i == size(m)) return 0;
        int e = n.size() - 1 - (i - s);
        if(dp[i][s] == -1) 
            dp[i][s] = max(m[i] * n[s] + solver(i + 1, n, m, s + 1), m[i] * n[e] + solver(i + 1, n, m, s));
        return dp[i][s];
    }
    
    int maximumScore(vector<int>& nums, vector<int>& multipliers) {
        memset(dp, -1, sizeof dp);
        int score = solver(0, nums, multipliers, 0);
        return score;
    }
};

Upvotes: 0

Andreas
Andreas

Reputation: 159135

The logic deciding whether to take the next value from the start or end of nums is incorrect.

Your code matches up numbers like this:

 -5    -3    -3    -2     7     1    nums
  │     │     ┌─────┼─────┼─────┘
  │     │     │     │  ┌──┘
  │     │     │     └──┼──┐
  │     │     │     ┌──┘  │
-10    -5     3     4     6         multipliers
  =     =     =     =     =
 50 +  15 +   3 +  28 + -12 =  84

That is because, on the 3rd iteration, the logic compares -3(start) * 3 = -9 vs 1(end) * 3 = 3, and chooses the value from the end, since 3 > -9.

However, if you take the cost of the negative value on the 3rd iteration, instead of on the 5th iteration, the result is higher.

 -5    -3    -3    -2     7     1    nums
  │     │     │           │     │
  │     │     │     ┌─────┼─────┘
  │     │     │     │     │
-10    -5     3     4     6         multipliers
  =     =     =     =     =
 50 +  15 +  -9 +   4 +  42 = 102

Don't know if there's a better way than brute-force, but it will find the correct solution.

static void solve(int[] nums, int[] multipliers) {
    if (multipliers.length > 30)
        throw new IllegalArgumentException("Too many multipliers (max 30): " + multipliers.length);
    final int end = 1 << multipliers.length;
    int maxSum = Integer.MIN_VALUE, maxBits = 0;
    for (int bits = 0; bits < end; bits++) {
        int sum = calc(nums, multipliers, bits, null);
        if (sum > maxSum) {
            maxSum = sum;
            maxBits = bits;
        }
    }
    StringBuilder expr = new StringBuilder();
    calc(nums, multipliers, maxBits, expr);
    System.out.println(expr);
}

private static int calc(int[] nums, int[] multipliers, int bits, StringBuilder expr) {
    int sum = 0, idx0 = 0, idx1 = nums.length;
    for (int i = 0; i < multipliers.length; i++) {
        boolean fromStart = ((bits & (1 << i)) == 0);
        int num = (fromStart ? nums[idx0++] : nums[--idx1]);
        sum += multipliers[i] * num;
        if (expr != null) {
            if (i != 0)
                expr.append(" + ");
            expr.append(multipliers[i]).append(" * ").append(num).append(fromStart ? "(start)" : "(end)");
        }
    }
    if (expr != null)
        expr.append(" = ").append(sum);
    return sum;
}

Test

solve(new int[] {-5,-3,-3,-2,7,1}, new int[] {-10,-5,3,4,6});

Output

-10 * -5(start) + -5 * -3(start) + 3 * -3(start) + 4 * 1(end) + 6 * 7(end) = 102

Of course, without all that extra code for printing the expression, the code is much smaller:

static int solve(int[] nums, int[] multipliers) {
    if (multipliers.length > 30)
        throw new IllegalArgumentException("Too many multipliers (max 30): " + multipliers.length);
    final int end = 1 << multipliers.length;
    int maxSum = Integer.MIN_VALUE;
    for (int bits = 0; bits < end; bits++) {
        int sum = 0, idx0 = 0, idx1 = nums.length;
        for (int i = 0; i < multipliers.length; i++)
            sum += multipliers[i] * ((bits & (1 << i)) == 0 ? nums[idx0++] : nums[--idx1]);
        maxSum = Math.max(maxSum, sum);
    }
    return maxSum;
}

The performance of this brute-force approach is O(2m)

Upvotes: 3

Related Questions