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
Related
The problem:
Given an array of integers nums containing n + 1 integers where each integer is in the range [1, n] inclusive.
There is only one repeated number in nums, return this repeated number.
You must solve the problem without modifying the array nums and uses only constant
extra space.
Here is one of the possible solution using binary search
class Solution(object):
def findDuplicate(self, nums):
beg, end = 1, len(nums)-1
while beg + 1 <= end:
mid, count = (beg + end)//2, 0
for num in nums:
if num <= mid: count += 1
if count <= mid:
beg = mid + 1
else:
end = mid
return end
Example 1:
Input: nums = [1,3,4,2,2]
Output: 2
Example 2:
Input: nums = [3,1,3,4,2]
Output: 3
Can someone please explain this solution for me? I understand the code but I don't understand the logic behind this. In particular, I do not understand how to construct the if statements (lines 7 - 13). Why and how do you know that when num <= mid then I need to do count += 1 and so on. Many thanks.
The solution keeps halving the range of numbers the answer can still be in.
For example, if the function starts with nums == [1, 3, 4, 2, 2], then the duplicate number must be between 1 and 4 inclusive by definition.
By counting how many of the numbers are smaller than or equal to the middle of that range (2), you can decide if the duplicate must be in the upper or lower half of that range. Since the actual number is greater (3 numbers are lesser than or equal to 2, and 3 > 2), the number must be in the lower half.
Repeating the process, knowing that the number must be between 1 and 2 inclusive, only 1 number is less than or equal to the middle of that range (1), which means the number must be in the upper half, and is 2.
Consider a slightly longer series: [1, 2, 5, 6, 3, 4, 3, 7]. Between 1 and 7 lies 3, 4 numbers are less than or equal to 3, so the number must be between 1 and 3. Between 1 and 3 lies 2, 2 numbers are less than or equal to 2, so the number must be over 2, which leaves 3.
The solution will iterate over all n elements of nums a limited number of times, since it keeps halving the search space. It's certainly more efficient than the naive:
def findDuplicate(self, nums):
for i, n in enumerate(nums):
for j, m in enumerate(nums):
if i != j and n == m:
return n
But as user #fas suggests in the comments, this is better:
def findDuplicate(nums):
p = 1
while p < len(nums):
p <<= 1
r = 0
for n in nums:
r ^= n
for n in range(len(nums), p):
r ^= n
return r
This is how given binary search works. Inside binary search you have implementation of isDuplicateLessOrEqualTo(x):
mid, count = (beg + end)//2, 0
for num in nums:
if num <= mid: count += 1
if count <= mid:
return False # In this case there are no duplicates less or equal than mid.
# Actually count == mid would be enough, count < mid is impossible.
else:
return True # In this case there is a duplicate less or equal than mid.
isDuplicateLessOrEqualTo(x) is a non-decreasing function (assume x has a duplicate, then for all i < x it's false and for all i >= x it's true), that's why you can run binary search over it.
Each iteration you run through the array, which gives you overall complexity O(n log n) (where n is size of array).
There's a faster solution. Note that xor(0..(2^n)-1) = 0 for n >= 2, because there are 2^(n-1) ones for each bit position and it's an even number, for example:
0_10 = 00_2
1_10 = 01_2
2_10 = 10_2
3_10 = 11_2
^
2 ones here, 2 is even
^
2 ones here, 2 is even
So by xor-ing all the numbers you'll receive exactly your duplicate number. Let's write it:
class Solution(object):
def nearestPowerOfTwo(number):
lowerBoundDegreeOfTwo = number.bit_length()
lowerBoundDegreeOfTwo = max(lowerBoundDegreeOfTwo, 2)
return 2 ** lowerBoundDegreeOfTwo
def findDuplicate(self, nums):
xorSum = 0
for i in nums:
xorSum = xorSum ^ i
for i in range(len(nums), nearestPowerOfTwo(len(nums) - 1)):
xorSum = xorSum ^ i
return xorSum
As you can see that gives us O(n) complexity.
If anyone is interested in a different approach (not binary search) to solve this problem:
Sum all elements of the array - we will call it sumArray - the time complexity is O(n).
Sum all numbers from 1 to n (inclusive) - we will call it sumGeneral - this is simply (n * (n+1) / 2) - the time complexity is O(1).
Return the result of sumArray - sumGeneral
In total, the time complexity is O(n) (you cannot do better since you have to look at all elements of the array, potentially the repeated one is at the end), and additional space complexity is O(1).
(If you could use O(n) additional space complexity you could use a hash table)
Write a function that given an array of A of N int, returns the smallest positive(greater than 0) that does not occur in A.
I decided to approach this problem by iterating through the list after sorting it.
The value of the current element would be compared to the value of the next element. Because the list is sorted, the list should follow sequentially until the end.
However, if there is a skipped number this indicates the smallest number that does not occur in the list.
And if it follows through until the end, then you should just add one to the value of the last element.
def test():
arr = [23,26,25,24,28]
arr.sort()
l = len(arr)
if arr[-1] <= 0:
return 1
for i in range(0,l):
for j in range(1,l):
cur_val = arr[i]
next_val = arr[j]
num = cur_val + 1
if num != next_val:
return num
if num == next_val: //if completes the list with no skips
return arr[j] + 1
print(test())
I suggest that you convert to a set, and you can then efficiently test whether numbers are members of it:
def first_int_not_in_list(lst, starting_value=1):
s = set(lst)
i = starting_value
while i in s:
i += 1
return i
arr = [23,26,25,24,28]
print(first_int_not_in_list(arr)) # prints 1
You can do the following:
def minint(arr):
s=set(range(min(arr),max(arr)))-set(arr)
if len(s)>0:
return min(set(range(min(arr),max(arr)))-set(arr)) #the common case
elif 1 in arr:
return max(arr)+1 #arr is a complete range with no blanks
else:
return 1 #arr is negative numbers only
You can make use of sets to achieve your goal.
set.difference() method is same as relative complement denoted by A – B, is the set of all elements in A that are not in B.
Example:
Let A = {1, 3, 5} and B = {1, 2, 3, 4, 5, 6}. Then A - B = {2, 4, 6}.
Using isNeg() method is used to check whether given set contains any negative integer.
Using min() method on A - B returns the minimum value from set difference.
Here's the code snippet
def retMin(arrList):
min_val = min(arrList) if isNeg(arrList) else 1
seqList=list(range((min_val),abs(max(arrList))+2))
return min(list(set(seqList).difference(arrList)))
def isNeg(arr):
return(all (x > 0 for x in arr))
Input:
print(retMin([1,3,6,4,1,2]))
Output:
5
Input:
print(retMin([-2,-6,-7]))
Output:
1
Input:
print(retMin([23,25,26,28,30]))
Output:
24
Try with the following code and you should be able to solve your problem:
def test():
arr = [3,-1,23,26,25,24,28]
min_val = min(val for val in arr if val > 0)
arr.sort()
l = len(arr)
if arr[-1] <= 0:
return 1
for i in range(0,l):
if arr[i] > 0 and arr[i] <= min_val:
min_val = arr[i] + 1
return min_val
print(test())
EDIT
It seems you're searching for the the value grater than the minimum positive integer in tha array not sequentially.
The code it's just the same as before I only change min_val = 1 to:
min_val = min(val for val in arr if val > 0), so I'm using a lambda expression to get all the positive value of the array and after getting them, using the min function, I'll get the minimum of those.
You can test it here if you want
Given an array of N positive integers, ranging from index 0 to N - 1, how can I find a contiguous subarray of length K with the minimum range possible. In other words, max(subarray) - min(subarray) is minimised. If there are multiple answers, any is fine.
For example, find the subarray of length 2 with the smallest range from [4, 1, 2, 6]
The answer would be [1, 2] as 2 - 1 = 1 gives the smallest range of all possible contiguous subarrays.
Other subarrays are [4, 1] (range 3), [2, 6] (range 4)
I'm using python and so far I've tried a linear search with min() max() functions and it just doesn't seem efficient to do so. I've thought of using a minheap but I'm not sure how you would implement this and I'm not even sure if it would work. Any help would be much appreciated.
edit: code added
# N = length of array_of_heights, K = subarray length
N, K = map(int, input().split(' '))
array_of_heights = [int(i) for i in input().split(' ')]
min_min = 100000000000000000000
# iterates through all subarrays in the array_of_heights of length K
for i in range(N + 1 - K):
subarray = land[i : i + K]
min_min = min(max(subarray)-min(subarray), min_min)
print(min_min)
There is linear-time algorithm O(N)for getting min or max in moving window of specified size (while your implementation has O(N*K) complexity)
Using deque from collections module you can implement two parallel deques keeping minumum and maximum for current window position and retrieve the best difference after the only walk through the list.
import collections
def mindiff(a, k):
dqmin = collections.deque()
dqmax = collections.deque()
best = 100000000
for i in range(len(a)):
if len(dqmin) > 0 and dqmin[0] <= i - k:
dqmin.popleft()
while len(dqmin) > 0 and a[dqmin[-1]] > a[i]:
dqmin.pop()
dqmin.append(i)
if len(dqmax) > 0 and dqmax[0] <= i - k:
dqmax.popleft()
while len(dqmax) > 0 and a[dqmax[-1]] < a[i]:
dqmax.pop()
dqmax.append(i)
if i >= k - 1:
best = min(best, a[dqmax[0]]-a[dqmin[0]])
return best
print(mindiff([4, 1, 2, 6], 2))
You could use numpy to improve execution time.
Example:
def f1(l,k):
subs = np.array([l[i:i+k] for i in range(len(l)-k+1)])
return np.min(subs.max(axis=1) - subs.min(axis=1))
Small test (f2 is your function here).
>>> arr = np.random.randint(100,size=10000)
>>> timeit.timeit("f1(arr,4)",setup="from __main__ import f1,f2,np,arr",number=1)
0.01172515214420855
>>> timeit.timeit("f2(arr,4)",setup="from __main__ import f1,f2,np,arr",number=1)
14.226237731054425
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.
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.