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
    
Asked By: odaiwa

||

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)
Answered By: Epsi95

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
Answered By: MisterMiyagi

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
Answered By: orlp

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.

Answered By: user3431635
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.