问题
I am doing google foobar challenge power hungry. I am failing in one test case out of 5 test cases which are hidden. Here is my code -
def answer(b):
from itertools import combinations
arr = []
for i in range(1,len(b)+1):
comb = combinations(b,i)
for j in list(comb):
mul = 1
for x in j:
mul *= x
if mul > 1000:
break
else:
arr.append(mul)
return str(max(arr))
Task is mentioned below -
Power Hungry
Commander Lambda's space station is HUGE. And huge space stations take a LOT of power. Huge space stations with doomsday devices take even more power. To help meet the station's power needs, Commander Lambda has installed solar panels on the station's outer surface. But the station sits in the middle of a quasar quantum flux field, which wreaks havoc on the solar panels. You and your team of henchmen has been assigned to repair the solar panels, but you can't take them all down at once without shutting down the space station (and all those pesky life support systems!).
You need to figure out which sets of panels in any given array you can take offline to repair while still maintaining the maximum amount of power output per array, and to do THAT, you'll first need to figure out what the maximum output of each array actually is. Write a function answer(xs) that takes a list of integers representing the power output levels of each panel in an array, and returns the maximum product of some non-empty subset of those numbers. So for example, if an array contained panels with power output levels of [2, -3, 1, 0, -5], then the maximum product would be found by taking the subset: xs[0] = 2, xs[1] = -3, xs[4] = -5, giving the product 2*(-3)*(-5) = 30. So answer([2,-3,1,0,-5]) will be "30".
Each array of solar panels contains at least 1 and no more than 50 panels, and each panel will have a power output level whose absolute value is no greater than 1000 (some panels are malfunctioning so badly that they're draining energy, but you know a trick with the panels' wave stabilizer that lets you combine two negative-output panels to produce the positive output of the multiple of their power values). The final products may be very large, so give the answer as a string representation of the number.
Languages
To provide a Python solution, edit solution.py To provide a Java solution, edit solution.java
Test cases
Inputs: (int list) xs = [2, 0, 2, 2, 0] Output: (string) "8"
Inputs: (int list) xs = [-2, -3, 4, -5] Output: (string) "60"
Use verify [file] to test your solution and see how it does. When you are finished editing your code, use submit [file] to submit your answer. If your solution passes the test cases, it will be removed from your home folder.
If possible, please suggest where I am mistaking in my code? Thanks.
回答1:
Your current algorithm won't scale to handle 50 panels since you would have to generate all 2**50 subsets of subarrays.
Initial Algorithm
From https://www.geeksforgeeks.org/maximum-product-subset-array/
This method has O(n) complexity (as compared to the O(2^n) of the posted method).
from random import randint
def maxProductSubset(a, n):
if n == 1:
return a[0]
# Find count of negative numbers, count
# of zeros, maximum valued negative
# number and product of non-zero numbers
max_neg = -999999999999
count_neg = 0
count_zero = 0
prod = 1
for i in range(n):
# If number is 0, we don't
# multiply it with product.
if a[i] == 0:
count_zero += 1
continue
# Count negatives and keep
# track of maximum valued negative.
if a[i] < 0:
count_neg += 1
max_neg = max(max_neg, a[i])
prod = prod * a[i]
# If there are all zeros
if count_zero == n:
return 0
# If there are odd number of
# negative numbers
if count_neg & 1:
# Exceptional case: There is only
# negative and all other are zeros
if (count_neg == 1 and count_zero > 0 and
count_zero + count_neg == n):
return 0
# Otherwise result is product of
# all non-zeros divided by maximum
# valued negative.
prod = int(prod / max_neg)
return str(prod) # Problem asks for string to be returned
# Test Code
if __name__ == '__main__':
big_array = [randint(-1000, 1000) for _ in range(51)]
tests = [[-1], [-1, 0], [2, 0, 2, 2, 0], [-2, -3, 4, -5], [ -1, -1, -2, 4, 3 ], big_array ]
for t in tests:
print('array {} \n\t max: {}'.format(t, maxProductSubset(t, len(t))))
Output
array [-1]
max: -1
array [-1, 0]
max: 0
array [2, 0, 2, 2, 0]
max: 8
array [-2, -3, 4, -5]
max: 60
array [-1, -1, -2, 4, 3]
max: 24
array [696, 254, 707, 730, 252, 144, 18, -678, 921, 681, -665, 421, -501, 204, 742, -609, 672, -72, 339, -555, -736, 230, -450, 375, 941, 50, 897, -192, -912, -915, 609, 100, -933, 458, -893, 932, -590, -209, 107, 473, -311, 73, 68, -229, 480, 41, -235, 558, -615, -289, -643]
max: 112783193423281396421025291063982496313759557506029207349556366834514274891010648892576460433185005069070271452630069726538629120
Strategy
Code for algorithm based upon the following facts:
- If there are even number of negative numbers and no zeros, result is simply product of all
- If there are odd number of negative numbers and no zeros, result is product of all except the largest valued negative number.
- If there are zeros, result is product of all except these zeros with one exceptional case. The exceptional case is when there is one negative number and all other elements are 0. In this case, result is 0.
Alternate Algorithm
from functools import reduce
from itertools import combinations
from random import randint
def answer(a, n):
def prod(arr):
" Multiply elements of array "
return reduce((lambda x, y: x * y), arr, 1)
def max_single_sign_prod(arr):
" Find max product of array assuming all element are same sign "
if arr[0] == 0:
return 0 # all zero
if arr[0] > 0:
return proc(arr) # all positive
# all negative
p = prod(arr)
if len(arr) > 1 and len(arr) % 2:
return p // max(arr)
else:
return p
# Generate all positive, all negative and all zero sublists of arr
pos = [i for i in a if i > 0]
neg = [i for i in a if i < 0]
zeros = [i for i in a if i == 0]
# Find non-empty sublists
b = [x for x in [pos, neg, zero] if len(x) > 0]
products = list(map(max_single_sign_prod, b))
# Find optimal combinations of these product to product max
# There's only 3**2 or 9 combinations to try
max_product = max(prod(c) for c in list(comb) for comb in combinations(products, i) for i in range(len(b)+1))
return str(max_product)
if __name__ == '__main__':
big_array = [randint(-1000, 1000) for _ in range(51)]
tests = [[-1], [1], [-1, 0], [2, 0, 2, 2, 0], [-2, -3, 4, -5], [ -1, -1, -2, 4, 3 ], big_array ]
for t in tests:
print('array {} \n\t max: {}'.format(t, maxProductSubset(t, len(t))))
Strategy
We generate three subsequences from the array:
- all positive numbers
- all zeros elements
- all negative elements
The maximum product for each of these sequences is as follows:
- all positive -- the product of all the numbers
- all zeros -- zero
- all negative -- product of all numbers (for even length) else divide the product by the max (if odd length)
We compute the maximum product for each of the non-empty sequences (i.e. all positive, zeros, and negative).
This results in from 1 to 3 products corresponding to the non-empty subsequences.
Our answer is to find the combination of the 1 to 3 products that provides the maximum value.
There are at most 3**2 combinations so this is easily computed.
回答2:
Brute forcing this is intractible. Combinations of 50 items of any size r
is astronomically huge.
Consider that if you have an even number of negative numbers in your final selection, you'll have a net positive result. Select all of the positive numbers in the list, then select the smallest (absolute value largest) k
negative numbers in the list where k % 2 == 0
(i.e. k
is even) and k
is as large as possible.
Said differently,
- Take all the positive numbers. We love positive numbers and they always help us.
- Take all of the negative numbers.
- If you have an odd number of negative numbers, omit the one with the largest value (closest to zero).
- Take the product of the numbers you took after step 3 and return it.
As mentioned by Simon, there's an edge case for a single negative number. All we can do is return it. Similarly, return 0 for situations with no positives, a single negative number and one or more zeroes.
回答3:
So, I worked out the solution and it solved all of my test cases. Bit of an unconventional solution:
First, check if the array has all zeros, return 0 in that case
Next, check if there is only one element, and it is negative, return that number
Next, check if there is only one negative number and the rest are zero, return zero in this case.
These are the only exception cases in the program.
The next steps are simple:
Find out the product of all the non-zero numbers.
If the product is positive, return that number, as it is the largest possible value.
If the product is negative, divide the number by the least negative number, and return the answer!
def solution(xs): if(xs.count(0) == len(xs)): return(str(0)) if(len(xs) == 1 and len([n for n in xs if n < 0]) == 1): return(str(xs[0])) if(len([n for n in xs if n < 0]) == 1 and xs.count(0) == len(xs)-1): return(str(0)) Val = 1 for i in xs: if (i != 0 and i <= 1000): Val *= i if Val < 0: BigNeg = max([n for n in xs if n < 0]) Val = Val/BigNeg return(str(int(Val)))
回答4:
Your code would fail for the test case b = [-1]
. The maximum product in this case is 1 (the product of the empty subset).
来源:https://stackoverflow.com/questions/59525299/google-foobar-challenge-power-hungry-failing-test-no-3-hidden-out-of-5-test