Amazon Interview Question
SDE-2sCountry: India
Interview Type: In-Person
Good solution when the array is int, but not generic enough to handle double array (what if there are elements like 0.001 or -0.37); Refined version of Kadane's algorithm is more generic.
This is a standard DP problem. Trick is to keep track of min and max of the subarray ending at i in the array indices 0 to i. While calculating the min or max, we also need to examine max or min respetively.
I'll post the code in a couple of hours.
Algorithm will be O(n)
You can see kadane's algorithm for the case of Sum. Product is just more refined problem, which uses the same algorithm.
Thank YD for reminding. I misunderstood the question.
Here's an O(n) solution for max product (inspired by the "longest valid parentheses" problem):
static int product(int A[], int begin, int end)
{
int i, step, mh, ma;
step = begin>end?-1:1;
ma = A[begin]; mh = 1;
for (i = begin; i != end; i += step) {
mh *= A[i];
if (mh > ma)
ma = mh;
if (A[i] == 0)
mh = 1;
}
return ma;
}
int max_subarray_product(int A[], int n)
{
int x, y;
x = product(A, 0, n-1);
y = product(A, n-1, 0);
return x>y?x:y;
}
#include <stdio.h>
#include <stdlib.h>
void main (void)
{
//int tab[10]={4,5,8,0,13,-3,4,15,-2,5};
int tab[10]={4,5,5,10,-1,7,100,2,0,2000000};
int i;
int mux=1;
int max=1;
int x=0;
int pos_x=0;
int pos_y=0;
for(i=0; i<10; i++)
{
mux= mux*tab[i];
if(mux > max){
max=mux;
pos_x=x;
pos_y=i;
}
else{
if(mux==0 || mux < 0){
mux=1;
x=i+1;}
}
}
printf(" pos_x=%d and pos_y=%d \n", pos_x,pos_y);
}
1) Call the original set S. Go through set S and remove all 0s, count the negative numbers, and mark the smallest negative number. Also note if a 0 was removed. Call this new set S'
2) if there is an even number of negative numbers return the product of S'
3) if there is an odd amount of negative numbers remove the smallest negative number from S' and return the product of S'. Corner case: if the size of S' is 1 and a zero was removed, return 0.
#include<iostream>
using namespace std;
int a[31]={15,3,-10,0,-20,23,25,2,-4,19,33,-39,41,-48,37,21,65,-73,69,28,46,-88,93,52,-56,44,98,-7,-9,-100,121};
int main()
{
int min=0;
int c=0,t;
for(int i=0;i<31;i++)
{
if(a[i]<min)
min=a[i];
}
int mul=1;
for(int i=0;i<31;i++)
{
if(a[i]<0)
{
if(min<a[i])
{
min=a[i];
t=i;
}
c++;
}
}
//cout<<min<<"\n";
if(c%2!=0)
a[t]=0;
for(int i=0;i<30;i++)
{
if(a[i]!=0)
{
mul*=a[i];
}
}
cout<<mul;
}
We are looking for the maximum product of an array elements. It apparent that we should ignore zeros since considering zeros simplifies the problem to find the maximum product of sub-arrays that are between these zeros (if there is only one zero, the max product of its left values and right values). If this is an acceptable assumption, it is also apparent that the product of the entire array elements is the answer if there is no negative values. This is also true if there exists even number of negative values. Hence, we can check and see if there are even or odd number of negative values and find the required maximum product accordingly.
void MaxProductSubArray(int *a, int n)
{
int cnt=0,i;
int prod=1;
int max=INT_MIN,I=INT_MIN;
for(i=0;i<n;i++)
{
if(a[i]<0)
cnt++;
if(a[i]!=0)
prod*=a[i];
}
if(cnt%2==0)
printf("%d\n",prod);
else
{
for(i=0;i<n;i++)
{
if(a[i]<0)
{
if(prod/a[i]>max)
{
max=prod/a[i];
I=i;
printf("---> %d\t%d\n",i,a[i]);
}
}
}
printf("\nMAX:\t%d\n",max);
}
}
}
My code that passed Leetcode OJ:
Explanations in changhaz(dot)wordpress(dot)com
class Solution {
public:
int maxProduct(int A[], int n) {
if (n==0) return 0;
int maxi = 1, mini = 1;
int out = INT_MIN;
for (int i=0;i<n;i++) {
int oldmaxi = max(maxi,1);
if (A[i] > 0) {
maxi = oldmaxi*A[i];
mini *= A[i];
} else {
maxi = mini*A[i];
mini = oldmaxi*A[i];
}
out = max(out,maxi);
}
return out;
}
};
Take a logarithm of each number, at this point the problem reduces to largest sum of subarray problem, which can be easily solves with Kadane's algorithm.
If the interviewer insists on using integers, the problem can be solved with a modified Kadane's algorithm, which keeps track of the largest and smallest product.
For an array with both positive and negative numbers we can notice that:
1. zero is to be ignored unless the array contains exactly 2 numbers {-v, 0}
2. Positive numbers are always wanted
3. Negative numbers are wanted as long as there is an even number of them
and in this case you want the smallest ones so to create the largest positive
product of them.
Because of the mixture you have to start by sorting them o(nlogn)
once sorted you can find the answer in a single scan of the sorted array while:
1. keeping track of the number negative numbers - ignore the biggest (closest to zero) negative number if there is an odd number of negative numbers.
2. Ignore 0 if possible (only one case require the use of 0)
3. Once reaching at the positive numbers continue to calculate till the end.
for(i=0;i<n;i++)
{
if(a[i]!=0)
{
if(currValue*a[i]>curValue)
maxProd=(curValue*a[i]>maxProd?currValue*a[i]:maxProd);
curValue=curValue*a[i];
}
}
return max;
This wont work for everything, here are some examples it will fail for:
1. The array {-1,0} --> the mux product is 0, your code ignores 0
2. {-2,-1,-9} --> So the question is do we have to find a solution of consecutive numbers In the array or just select the best numbers to include. for the first option that will be {-1,-9} for the seconds it is {-2, -9}
An O(n) solution:
int max_subarray(int A[], int n)
{
int i, mh, ma;
mh = ma = A[0];
for (i = 1; i < n; i++) {
mh += A[i];
if (mh < A[i])
mh = A[i];
if (mh > ma)
ma = mh;
}
return ma;
}
@Nitin: No, he's considering all the cases. Let me explain his strategy with an example,
[1, -2, 3, 4, -5, 0, 2, 5, 1, 0, 8, -3, 1, 0, 0, 1, 3, -5, 7, -6, 2, -2, 2]
Consider all maximal non-zero subarrays:
[1, -2, 3, 4, -5]: there are 2(even) -ve numbers so take the product as it is, i.e. 120
[2, 5, 1]: there are 0(even) -ve numbers so take the product as it is: 10
[8, -3, 1]: there is 1(odd) -ve numbers, so take the two positive products, i.e. 8 and 1
[1, 3, -5, 7, -6, 2, -2, 4]: there are 3(odd) -ve numbers, so take the two biggest positive products, i.e 1 to -2 = 1260 and 7 to 4 = 672
Clearly the biggest product is 1260.
I just want to mention one thing: initialize the maximum global sum to -infinity. If there is at least one zero in the array, initialize it to 0.
@Nitin R. Gupta
Seems you have barely understood the algorithm. See @anotherguy's comments for an explanation.
Sounds good, except step 2 should contain a third case for which there is only one number, which is negative, between begin and end.
@Erasmus:
What if you have an array with all negatives? You are not considering any negative products, so your answer will be undefined in this case.
I think we should initialize the max. global sum to -infinity, then consider all positive products as you suggested, and all non-positive numbers individually as well!
@anotherguy
You have got a nice use-case, the one with all -ve numbers. In this case, you would not want to check all non-positive numbers individually. Instead, It again boils down to whether you have an even number of -ve numbers or an odd number of them.
If the count parity is even, you will get maximum subarray positive product by multiplying all of the -ve numbers.
If the count parity is odd, you will get maximum subarray positive product by either multiplying from 0 to n-2 or from 1 to n-1
Both of the above cases are anyway handled by my algorithm in step 2 (and beyond) as show below
>>2. Between begin and end, take the count, c of the number of -ve numbers and note the 'first'and 'last' positions of -ve numbers
However, to address your issue, I need to slightly modify my procedure of demarcating the 'end' of the array in the step 1. The below statement can be changed from:
>> 1. From 'begin' traverse the array until you find a 0 and demarcate it as 'end'.
to:
>> 1. From 'begin' traverse the array until you find a 0 or reach the end of the array and demarcate it as 'end'.
However, the un-handled test case suggested by @Anonymous is more fundamental and is the one which indeed requires checking all -ve numbers individually. For ex: if we you have the array [0,-1,0,-2,0,-3,0], you will have to check each -ve number individually and pick the min of them to give you the maximum subarray (-ve) product.
@Anonymous
Excellent test case, thanks! For your type of input, say [0,-1,0]. my algorithm may not crash, but it would wrongly return 0. Instead, it should return -1 and yes, step 2 certainly needs modification.
When there are odd number of -ve numbers between begin and end, with an additional check to see if there is only one element between begin and end, we can return the lone -ve number's value itself as the max product of the subarray.
Does not work, even for positive numbers.
Just tried running your code with {1, 2, 3, 0, 4, 5}, gives 120
@ anotherguy 120 for the array {1,2,3,0,4,5} is a correct outcome since the question is asking for a maximum sub-array and not a maximum sequence i.e., it is not concern if the values are sequential.
@Aadish, would you please explain why you suggest so? I tried it on {1, -2, 3, 4, -5, 0} and {1, -2, 3, 4, -5, 0, 2, 5, 1, 0, 8, -3, 1, 0, 0, 1, 3, -5, 7, -6, 2, -2, 2}. Thanks! :)
Count the number of negatives in the array, at the same time check for any zeroes in the array.
If there is a zero in the array, get the max-product from the left and right sub-arrays and find the max of them.
If there are no zeroes :
1. if no. of negatives is even, max-product is the product of all numbers.
2. if it is odd, iterate the array in both forward and backward directions and compute the product until you discover a negative number. Now, ignore the side where the product's absolute value is lesser.
eg : [ -100, 2, 25, -1, 8, -5, 22]
no. of negatives are 3 here.
When you iterate the array from both directions : fwd-product is -100 and bwd-product is -110. So ignore the values in the forward direction. So the max-product is 44000
- prasanth September 13, 2013