Given a list consisting of 1 to 50 integers in the range of -1000 to 1000, calculate the maximum product of one or any number of integers within the list given.
My approach:
import itertools
def answer(xs):
cur = 1
dal = []
for i in range(len(xs), 0, -1):
for j in itertools.combinations(xs, i):
for x in j:
cur *= x
dal.append(cur)
cur = 1
dal.sort(reverse=True)
return str(dal[0])
The results timed out. I want to optimize the structure of the procedure to be as efficient as possible.
Going through all the combinations is a bad idea unless you have months for the calculation. If all numbers were positive, You would just multiply them all. If all were negative You would take even number of them. If You have to skip one, skip the biggest (-2 is bigger than -5). Adding zero to the mix returns always zero, which is worse than any of the previous cases. If there is no positive number and there are zero or one negative numbers, just take the biggest number You have. It can be zero or the only negative number You have.
def answer(xs):
mult = 1
valid = 0
for i in xs:
if i > 0:
mult *= i
valid = 1
negative = [i for i in xs if i<0]
negative.sort()
if(len(negative) & 1):
del negative[-1]
for i in negative:
mult *= i
valid = 1
if valid==0:
return max(xs)
return mult
and here are some test cases:
xs = [0]
print(xs,"->",answer(xs)) #[0] -> 0
xs = [-1]
print(xs,"->",answer(xs)) #[-1] -> -1
xs = [0,-1]
print(xs,"->",answer(xs)) #[0, -1] -> 0
xs = [-2,-3]
print(xs,"->",answer(xs)) #[-2, -3] -> 6
xs = [-2,-3,-4]
print(xs,"->",answer(xs)) #[-2, -3, -4] -> 12
xs = [-2,-3,0]
print(xs,"->",answer(xs)) #[-2, -3, 0] -> 6
xs = [-2,3]
print(xs,"->",answer(xs)) #[-2, 3] -> 3
maximum product can be achieved by multiplying all integers if count of negative is even else maximum product will be leaving the negative (closest to zero) and multiply all others.
for n=1 print the number as it is.
EDITED :
if len(mylist)==1:
print mylist[0]
else:
count=0
for i in mylist:
if i<0:
count+=1
if count>0:
mylist.sort()
if mylist[-1]==0:
print "0"
else:
ans=1
flag=1
for i in xrange(len(mylist)):
if mylist[i]>0 and flag==1:
ans/=mylist[i-1]
else:
ans*=mylist[i]
if flag==1:
ans/=mylist[-1]
print ans
else:
ans=1
for i in mylist:
if i>0:
ans*=i
print ans
and then return ans from your function.
this is a O(n) solution.
You could use a two-phase algorithm for O(n) time complexity. First multiply all the positive numbers with each other and in case there are no positive numbers pick the largest one. With reduce this can be easily done with one line.
On the following step filter out all negative numbers. If there's more than one multiply them all together. In case the multiplication results to negative number (= there's odd amount of negative numbers) divide the result with maximum of the negative numbers. Then multiply the product you got in step one with product of step 2 for the final result. In case product of step 1 was non-positive number then product of step 2 is the result.
from functools import reduce
nums = [3, -4, 5, -2, -3, 0, 1]
res = reduce(lambda x,y: x * y if x > 0 and y > 0 else max(x, y), nums)
negatives = [x for x in nums if x < 0]
if len(negatives) > 1:
neg = reduce(lambda x,y: x * y, negatives)
if neg < 0:
neg //= max(negatives)
res = max(res, 1) * neg
print(res)
Output:
180
If you're using Python 2 there's no need to import reduce since it's a built-in and instead of floordiv just use regular one.
This can be optimized in a few ways. First, instead of hosting everything in an array, have a variable maximum which is initialized to xs[0] and each product is checked against. Additionally, instead of doing the multiplication yourself, you can use mul from the operator module with reduce. Finally, I would use xrange as in Python 2 it does not create an array making it more efficient than range This would make your code look like this
from itertools import combinations
from operator import mul
def answer(xs):
maximum = xs[0]
one = 1 in xs
filter(lambda a: a != 0 and a != 1, xs)
if len(xs) == 0:
if one:
return 1
else:
return 0
for i in xrange(len(xs), 0, -1):
for j in combinations(xs, i):
prod = reduce(mul, j, 1)
if prod > maximum:
maximum = prod
return str(maximum)
I left the return as str(maximum), but you can return it as maximum which is an integer if you want.
Related
You are given the following array A, We need to calculate the total number of sub-arrays with XOR sum X were, The sub-array should satisfy the conditions (X+1) = (X^1). Here is my solution,
def getTotalXorOfSubarrayXors(arr, N):
X = 0
count = 0
for i in range(0, N):
for j in range(i, N):
for k in range(i, j + 1):
X = X ^ arr[k]
if X+1 == X^1:
count +=1
X = 0
return count
arr = [3, 5, 2, 4, 6]
N = len(A)
print(getTotalXorOfSubarrayXors(A, N))
But this solution has a time complexity of O(n^3) which exceeds my time limit for a large set of arrays. Is there is any way I can optimize this code to have less time complexity?
The condition (X+1) = (X^1) just means X must be even. So just count the even xors by using prefix-xor-counts. Takes O(n) time and O(1) space.
def getTotalXorOfSubarrayXors(A, _):
X = 0
counts = [1, 0]
total = 0
for a in A:
X ^= a & 1
total += counts[X]
counts[X] += 1
return total
Try it online! (with tests)
Operation X ^ 1 changes the last bit of a number. So ****1 becomes ****0 and vice versa.
So we can see that for odd values of X value of X ^ 1 is less than X, but for even X's value X ^ 1 is larger by one than X - just what we need.
Now we can count subarrays with even xor-sum. Note that we remember how many odd and even xorsums we already have for subarrays starting from zero index:
def Xors(arr, N):
oddcnt = 0
evencnt = 0
res = 0
x = 0
for p in arr:
x ^= p
if (x % 2):
res += oddcnt
oddcnt += 1
else:
evencnt += 1
res += evencnt
return res
I received interview question to find the non-empty subset of an array with the maximum product. I solved the task but one test out of five doesn't pass. I don't understand what I may have missed in my solution. (The task should be done in python 2.7)
Task is here:
I have an array of integers and I need to return the non-empty subset of elements with the maximum product of values. If I have an odd number of negative numbers in the array, I have to exclude one of them to make the selected product be positive.
If I have 0 inside, in general I'll want to exclude it, also. For example: for [2, 5, -2] result should be 10, for [-2,-5,-1, 0, 2] result should be 20.
I tried different edge cases like [-1], [1], [0], [0,0,0]
Solution is here:
from functools import reduce
def answer(arr):
selection = [n for n in arr if n !=0 and -1000<=n<=1000]
negative = [n for n in selection if n<0]
if len(negative) % 2 == 1:
selection.remove(max(negative))
if not selection:
return '0'
else:
return str(reduce(lambda x, y: x * y, selection))
A careful reading of the question indicates that answer([-5]) should yield solution -5, since it needs to select a non-empty subset of the input array. However, your code returns 0 for answer([-5]). So perhaps something like:
from functools import reduce
def answer(arr):
hasZero = any([n == 0 for n in arr])
selection = [n for n in arr if n !=0 and -1000<=n<=1000]
negative = [n for n in selection if n<0]
if len(negative) % 2 == 1 and (len(selection) > 1 or hasZero):
selection.remove(max(negative))
if not selection:
return '0'
else:
return str(reduce(lambda x, y: x * y, selection))
answer([-5])
# '-5'
answer([0, -5])
# '0'
I have an array of integers and I need to get their maximum possible value. If I have negative numbers and their total amount is uneven I have to exclude one of them to make an array positive.
If I have 0 inside and it can affect on result of my multiplication, I have to exclude it also.
For example: for [2, 5, -2] result should be 10, for [-2,-5,-1, 0, 2] result should be 20.
I implemented the task, but the system doesn't accept my solution, could you please take a look at my solution where I could make a mistake? I tried different edge cases like [-1], [1], [0], [0,0,0]
def answer(n):
arr = 0
res = 1
for number in n:
if number < 0:
arr += 1
n.sort()
while 0 in n: n.remove(0)
if not n:
return '0'
if len(n) == 1:
if n[0] < 0:
return '0'
elif arr % 2 != 0:
n.pop(arr - 1)
for x in n:
res *= x
return str(res)
It appears you are looking to multiply all numbers in a list, except for any zeroes and if there's an odd number of negative numbers, you are excluding the smallest negative number?
A simple solution:
from functools import reduce
def answer(numbers):
selection = [n for n in numbers if n != 0]
negative = [n for n in selection if n < 0]
if len(negative) % 2 == 1:
selection.remove(max(negative))
if not selection:
return 0
else:
return reduce(lambda x, y: x * y, selection)
print(answer([-2, -5, -1, 0, 2]))
I am currently working on a function that takes a sequence and returns the maximum increase from one element to the other at a higher index. However, the function is not returning the correct maximum increase.
I have put a for loop inside a for loop, then tried to return the maximum value out of all the differences, which did not work (it said 'int' object is not iterable)
def max_increase(seq):
i = 0
maximum_increase = 0
for i in range(len(seq)):
difference = 0
for j in range(i + 1, len(seq)):
difference = seq[j] - seq[i]
if 0 <= maximum_increase < difference:
maximum_increase = difference
return maximum_increase
For max_increase([1,2,3,5,0]), it should return 4 since from the differences list [1,2,4,-1,1,3,-2,2,-3,-5], the maximum is 4. However, my function returns a negative value, -1.
You have an indentation problem. This fixes it:
def max_increase(seq):
i = 0
maximum_increase = 0
for i in range(len(seq)):
difference = 0
for j in range(i + 1, len(seq)):
difference = seq[j] - seq[i]
if 0 <= maximum_increase < difference:
maximum_increase = difference
return maximum_increase
Given you have received help in debugging your code already, here is a short pythonic solution to the problem:
>>> l=[1,2,3,5,0]
>>> inc = (i-el for p, el in enumerate(l) for i in l[p:])
>>> max(inc)
4
but even better is one that avoids creating unnecessary slices (at the cost of reversing the sequence):
import itertools as it
def incs(seq):
pr = []
for el in reversed(seq):
print(f"{el} is compared with {pr}")
yield (i-el for i in pr)
pr.append(el)
seq = [1, 2, 3, 5, 0]
print("The max inc is", max(it.chain.from_iterable(incs(seq))))
which produces
0 is compared with []
5 is compared with [0]
3 is compared with [0, 5]
2 is compared with [0, 5, 3]
1 is compared with [0, 5, 3, 2]
The max inc is 4
Note: in case the increase is to be intended as the distance between the two numbers, i.e. always positive irrespective of sign, then make the change
yield (abs(i-el) for i in pr)
you can use:
my_l = [1,2,3,5,0]
max((e for i in range(len(my_l)) for e in (j - my_l[i] for j in my_l[i + 1:])))
output:
4
I'm tryin to design a function that, given an array A of N integers, returns the smallest positive integer (greater than 0) that does not occur in A.
This code works fine yet has a high order of complexity, is there another solution that reduces the order of complexity?
Note: The 10000000 number is the range of integers in array A, I tried the sort function but does it reduces the complexity?
def solution(A):
for i in range(10000000):
if(A.count(i)) <= 0:
return(i)
The following is O(n logn):
a = [2, 1, 10, 3, 2, 15]
a.sort()
if a[0] > 1:
print(1)
else:
for i in range(1, len(a)):
if a[i] > a[i - 1] + 1:
print(a[i - 1] + 1)
break
If you don't like the special handling of 1, you could just append zero to the array and have the same logic handle both cases:
a = sorted(a + [0])
for i in range(1, len(a)):
if a[i] > a[i - 1] + 1:
print(a[i - 1] + 1)
break
Caveats (both trivial to fix and both left as an exercise for the reader):
Neither version handles empty input.
The code assumes there no negative numbers in the input.
O(n) time and O(n) space:
def solution(A):
count = [0] * len(A)
for x in A:
if 0 < x <= len(A):
count[x-1] = 1 # count[0] is to count 1
for i in range(len(count)):
if count[i] == 0:
return i+1
return len(A)+1 # only if A = [1, 2, ..., len(A)]
This should be O(n). Utilizes a temporary set to speed things along.
a = [2, 1, 10, 3, 2, 15]
#use a set of only the positive numbers for lookup
temp_set = set()
for i in a:
if i > 0:
temp_set.add(i)
#iterate from 1 upto length of set +1 (to ensure edge case is handled)
for i in range(1, len(temp_set) + 2):
if i not in temp_set:
print(i)
break
My proposal is a recursive function inspired by quicksort.
Each step divides the input sequence into two sublists (lt = less than pivot; ge = greater or equal than pivot) and decides, which of the sublists is to be processed in the next step. Note that there is no sorting.
The idea is that a set of integers such that lo <= n < hi contains "gaps" only if it has less than (hi - lo) elements.
The input sequence must not contain dups. A set can be passed directly.
# all cseq items > 0 assumed, no duplicates!
def find(cseq, cmin=1):
# cmin = possible minimum not ruled out yet
size = len(cseq)
if size <= 1:
return cmin+1 if cmin in cseq else cmin
lt = []
ge = []
pivot = cmin + size // 2
for n in cseq:
(lt if n < pivot else ge).append(n)
return find(lt, cmin) if cmin + len(lt) < pivot else find(ge, pivot)
test = set(range(1,100))
print(find(test)) # 100
test.remove(42)
print(find(test)) # 42
test.remove(1)
print(find(test)) # 1
Inspired by various solutions and comments above, about 20%-50% faster in my (simplistic) tests than the fastest of them (though I'm sure it could be made faster), and handling all the corner cases mentioned (non-positive numbers, duplicates, and empty list):
import numpy
def firstNotPresent(l):
positive = numpy.fromiter(set(l), dtype=int) # deduplicate
positive = positive[positive > 0] # only keep positive numbers
positive.sort()
top = positive.size + 1
if top == 1: # empty list
return 1
sequence = numpy.arange(1, top)
try:
return numpy.where(sequence < positive)[0][0]
except IndexError: # no numbers are missing, top is next
return top
The idea is: if you enumerate the positive, deduplicated, sorted list starting from one, the first time the index is less than the list value, the index value is missing from the list, and hence is the lowest positive number missing from the list.
This and the other solutions I tested against (those from adrtam, Paritosh Singh, and VPfB) all appear to be roughly O(n), as expected. (It is, I think, fairly obvious that this is a lower bound, since every element in the list must be examined to find the answer.) Edit: looking at this again, of course the big-O for this approach is at least O(n log(n)), because of the sort. It's just that the sort is so fast comparitively speaking that it looked linear overall.