Finding number of positive numbers in list
Question:
I’m trying to find the number of positive numbers in the list using python and I want the code to run in O(log(n))
the list is of type Positive-Negative if there’s a negative number it will be on the right-hand side of the list and all the positives are on the left side.
for example, if the input is :
lst=[2,6,0,1,-3,-19]
the output is
4
I’ve tried some methods but I didn’t get the result that I wanted
this is the last form that I get until now:
def pos_neg(lst):
if int(len(lst)) is 0 or (int(len(lst)) is 1 and lst[0] <0):
return 0
elif len(lst) is 1 and lst[0] >=0:
return 1
leng = (int(len(lst))) // 2
counter = 0
index = 0
while(leng != 0):
if lst[leng] >=0 and lst[leng+1] <0:
index = leng
break
if lst[leng] >=0 and lst[leng + 1] >=0:
if int(len(lst)) < leng + int(len(lst)):
return 0
else:
leng = (leng + int(len(lst))) // 2
if lst[leng] <0 and lst[leng + 1] <0:
leng = leng // 2
return index
Answers:
You can use recursion. Every time the list is halved, so the complexity is O(logn)
def find_pos(start, end, l, count):
if(start > end):
return count
middle = start + (end-start)//2
if(l[middle] >= 0): # that means all left side is positive
count += (middle-start) + 1
return find_pos(middle+1, end, l, count)
else: # that means I am in wrong region
return find_pos(start, middle-1, l, count)
lst=[2,6,0,1,-3,-19]
find_pos(0, len(lst)-1, lst, 0)
>>> 4
Update:
If you want one function passing only lst
def find_positives(l):
return find_pos(0, len(l)-1, l, 0)
find_positives(lst)
What you describe is a bisection algorithm. The standard library provides value search bisection for ascending sequences, but it can be easily adjusted to search for positive/negative in sign-descending sequences:
def bisect_pos(nms):
"""
Do a right-bisect for positive numbers
:prams nms: numbers where positive numbers are left-aligned
This returns the index *after* the right-most positive number.
This is equivalent to the count of positive numbers.
"""
if not nms:
return 0
# the leftmost/rightmost search index
low_idx, high_idx = 0, len(nms)
while low_idx < high_idx:
mid_idx = (low_idx + high_idx) // 2
if nms[mid_idx] < 0: # negative numbers – search to the left
high_idx = mid_idx
else: # positive numbers – search to the right
low_idx = mid_idx+1
return low_idx
I usually find binary searches that repeatedly compute the middle difficult to confirm as correct, whereas constructing the index we’re looking for bit-by-bit is always clear to me. So:
def find_first_negative(l):
if not l or l[0] < 0: return 0
idx = 0 # Last positive index.
pot = 1 << len(l).bit_length()
while pot:
if idx + pot < len(l) and l[idx + pot] >= 0:
idx += pot
pot >>= 1
return idx + 1
Idea of algorithm is following:
you assign two variables: left = 0 and right=len(lst)-1
then cycle calculating middle index as middle = (left + right) // 2
and check sign of lst[middle]. Then assign left = middle or right = middle depending on this check. Then cycle repeats while left < right and not equal.
As result your middle element will point to last positive or first negative depending on how you make comparison.
I’m trying to find the number of positive numbers in the list using python and I want the code to run in O(log(n))
the list is of type Positive-Negative if there’s a negative number it will be on the right-hand side of the list and all the positives are on the left side.
for example, if the input is :
lst=[2,6,0,1,-3,-19]
the output is
4
I’ve tried some methods but I didn’t get the result that I wanted
this is the last form that I get until now:
def pos_neg(lst):
if int(len(lst)) is 0 or (int(len(lst)) is 1 and lst[0] <0):
return 0
elif len(lst) is 1 and lst[0] >=0:
return 1
leng = (int(len(lst))) // 2
counter = 0
index = 0
while(leng != 0):
if lst[leng] >=0 and lst[leng+1] <0:
index = leng
break
if lst[leng] >=0 and lst[leng + 1] >=0:
if int(len(lst)) < leng + int(len(lst)):
return 0
else:
leng = (leng + int(len(lst))) // 2
if lst[leng] <0 and lst[leng + 1] <0:
leng = leng // 2
return index
You can use recursion. Every time the list is halved, so the complexity is O(logn)
def find_pos(start, end, l, count):
if(start > end):
return count
middle = start + (end-start)//2
if(l[middle] >= 0): # that means all left side is positive
count += (middle-start) + 1
return find_pos(middle+1, end, l, count)
else: # that means I am in wrong region
return find_pos(start, middle-1, l, count)
lst=[2,6,0,1,-3,-19]
find_pos(0, len(lst)-1, lst, 0)
>>> 4
Update:
If you want one function passing only lst
def find_positives(l):
return find_pos(0, len(l)-1, l, 0)
find_positives(lst)
What you describe is a bisection algorithm. The standard library provides value search bisection for ascending sequences, but it can be easily adjusted to search for positive/negative in sign-descending sequences:
def bisect_pos(nms):
"""
Do a right-bisect for positive numbers
:prams nms: numbers where positive numbers are left-aligned
This returns the index *after* the right-most positive number.
This is equivalent to the count of positive numbers.
"""
if not nms:
return 0
# the leftmost/rightmost search index
low_idx, high_idx = 0, len(nms)
while low_idx < high_idx:
mid_idx = (low_idx + high_idx) // 2
if nms[mid_idx] < 0: # negative numbers – search to the left
high_idx = mid_idx
else: # positive numbers – search to the right
low_idx = mid_idx+1
return low_idx
I usually find binary searches that repeatedly compute the middle difficult to confirm as correct, whereas constructing the index we’re looking for bit-by-bit is always clear to me. So:
def find_first_negative(l):
if not l or l[0] < 0: return 0
idx = 0 # Last positive index.
pot = 1 << len(l).bit_length()
while pot:
if idx + pot < len(l) and l[idx + pot] >= 0:
idx += pot
pot >>= 1
return idx + 1
Idea of algorithm is following:
you assign two variables: left = 0 and right=len(lst)-1
then cycle calculating middle index as middle = (left + right) // 2
and check sign of lst[middle]. Then assign left = middle or right = middle depending on this check. Then cycle repeats while left < right and not equal.
As result your middle element will point to last positive or first negative depending on how you make comparison.