Reputation: 23
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
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
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