I am trying to solve LeetCode problem 152. Maximum Product Subarray:
Given an integer array
nums, find a subarray* that has the largest product, and return the product.The test cases are generated so that the answer will fit in a 32-bit integer.
Constraints:
1 <= nums.length <= 2 * 104-10 <= nums[i] <= 10- The product of any prefix or suffix of
numsis guaranteed to fit in a 32-bit integer.
* A subarray is a contiguous non-empty sequence of elements within an array.
My approach to this was go two ways:
one way was to multiply the consecutive numbers
the other was to ignore the consecutive product and start multiplication from the current number
and here's my code for this approach(in python) :
class Solution:
def maxProduct(self, nums: list[int]) -> int:
def func(nums,i,rs):
if i<0:
return 1
rs=nums[i]*rs
res=max((func(nums,i-1,rs)),func(nums,i-1,rs=1))
return res
i=len(nums)-1
rs=1
return func(nums,i,rs)
x=Solution()
print(x.maxProduct([2,3,-2,4]))
I should be getting the answer as 6 (since the maximum product subarray will be [2,3]), however, I'm getting an output of 1. What's wrong with my code???

First of all, your general idea is a brute force algorithm. This is very inefficient, and will not pass the LeetCode tests even when you fix the issues with the wrong return values.
But as you asked specifically about these wrong outputs and what is causing them, let's analyse it.
Issues in your code
1. Always returning 1
Your base case -- when arriving at
i < 0-- always returns 1. And when coming back from recursion, the max of 1 and 1 is still 1, so alsoreturn reswill return 1. There is actually no way this recursive function could return anything else than 1.It doesn't matter that
rswill often be different from 1. In the end it is not used to determine the final return value. You have a lot of multiplications going on, only to finally ignore that product.The first fix is to not ignore that product, and return it in the base case:
Now your code will return 6 for the example input.
2. Missing the third way
After applying the above fix, your code will not return the correct value yet for other inputs, like these:
The problem is that in your analysis of "two ways", there is a way missing: it is to not ignore the product so far, but consider it a candidate for the final result. In the above two examples, 4 is a valid candidate, but by ignoring it and starting with new products, you'll only find lesser products (in these examples), and return one of those. This is not good: 4 should get a chance to compare with those other products.
To fix that issue, your
max()call should consider this "third way" as well, and includers(without recursive call) as an argument tomax(). That will make your function also work for the above kinds of inputs.3. Assuming 1 as initial "product"
Then there are still other inputs for which your function will return the wrong result. For instance:
The expected output here is 0, but your function will return 1, which in fact is a product you can never get from such input. The cause is your assumption that you can use
rs=1any time you start a new product -- both in the main call and in a recursive call. This works often, but not if a zero is involved. So starting withrs=1is wrong. Always start with an actual value that is in the list, and then multiply that with a neighbor value, or don't. But not taking any value fromnumsand assuming that 1 is a solution is clearly wrong.To fix that for what concerns the main call, change this:
...to this:
You need a similar change in the recursive call. Change this:
to this:
This latter change, means that you include
nums[i], and so you should excludenums[i]from the "third way" discussed above.Corrected code
After applying the above fixes to your code, we get this:
This will return the correct response if enough space and time resources are available.
Brute force is not good enough
Your approach is really a brute force algorithm. All possible sublists are considered and the products they represent are calculated and compared. This is not efficient, and will not pass the LeetCode tests that provide a
numslist with 50 entries. Note that LeetCode will supply lists with up to 104 entries, so 50 really isn't a lot.Also, the recursion depth will become a problem, as the default stack limit will be reached before reaching the base case for larger inputs.
You'll have to come up with an entirely different algorithm.
Hints:
If a list has no zeroes, then you'll want to find a sublist that has an even number of negative values as then the product will be positive. Within that constraint, you'll want that list to include as many numbers as possible, as adding more numbers will not decrease the product (again, if we keep the number of negative values even). If the number of negative values is odd, then you'll want to either start the product after the first negative number, or stop before the last negative number.
If a list has zeroes, then solve the problem for the sublists between those zeroes, and then see if the maximum product for those is greater than 0, otherwise stick with 0.
Spoiler solution: