Teaching Kids Programming – Find Insertion Point in Sorted List via bisect_left or bisect_right


Teaching Kids Programming: Videos on Data Structures and Algorithms

If a list/array sorted, we can find the insertion point/index of given value x via Binary Search Algorithm – which takes O(LogN) time. In Python, we have bisect_left and bisect_right from the package bisect library.

python-bisect_left-and-bisect_right Teaching Kids Programming - Find Insertion Point in Sorted List via bisect_left or bisect_right algorithms binary search math python teaching kids programming youtube video

bisect_left

The bisect_left has the following function signature:

1
bisect_left(a, x, lo=0, hi=None, key=None)
bisect_left(a, x, lo=0, hi=None, key=None)

It returns the insertion point i where all elements at a[:i] is strictly smaller than x and all elements at a[i:] are bigger or equal then x. The lo and hi are optional parameters to specify the lower/upper index. The key can be also passed to give a customize key function:

If we go for the linear search, it will take O(N):

1
2
3
4
5
6
7
8
9
10
11
12
13
def bisect_left(a, x, lo=0, hi=None, key=None):
    if lo < 0:
        raise ValueError('lo must be non-negative')
    if hi is None:
        hi = len(a)
    for i in range(lo, hi):
        if key is None:
            v = a[i]
        else:
            v = key(a[i])
        if a[i] >= x:
            return i
    return hi
def bisect_left(a, x, lo=0, hi=None, key=None):
    if lo < 0:
        raise ValueError('lo must be non-negative')
    if hi is None:
        hi = len(a)
    for i in range(lo, hi):
        if key is None:
            v = a[i]
        else:
            v = key(a[i])
        if a[i] >= x:
            return i
    return hi

As the array is already sorted, we can binary search – this improves the time complexity to O(LogN).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def bisect_left(a, x, lo=0, hi=None, key=None):
    if lo < 0:
        raise ValueError('lo must be non-negative')
    if hi is None:
        hi = len(a)
    while lo < hi:
        mid = (lo + hi)//2
        if key is None:
            v = a[mid]
        else:
            v = key(a[mid])
        if a[mid] < x: 
            lo = mid+1
        else: 
            hi = mid
    return lo
def bisect_left(a, x, lo=0, hi=None, key=None):
    if lo < 0:
        raise ValueError('lo must be non-negative')
    if hi is None:
        hi = len(a)
    while lo < hi:
        mid = (lo + hi)//2
        if key is None:
            v = a[mid]
        else:
            v = key(a[mid])
        if a[mid] < x: 
            lo = mid+1
        else: 
            hi = mid
    return lo

bisect_right

The bisect_right takes the same parameters but behaves differently. It will return a insertion point i where all elements at a[:i] are smaller or equal to x and all elements at a[i:] are strictly larger than x:

The linear version is quite similar than above:

1
2
3
4
5
6
7
8
9
10
11
12
13
def bisect_right(a, x, lo=0, hi=None, key=None):
    if lo < 0:
        raise ValueError('lo must be non-negative')
    if hi is None:
        hi = len(a)
    for i in range(lo, hi):
        if key is None:
            v = a[i]
        else:
            v = key(a[i])
        if a[i] > x:
            return i
    return hi
def bisect_right(a, x, lo=0, hi=None, key=None):
    if lo < 0:
        raise ValueError('lo must be non-negative')
    if hi is None:
        hi = len(a)
    for i in range(lo, hi):
        if key is None:
            v = a[i]
        else:
            v = key(a[i])
        if a[i] > x:
            return i
    return hi

and the optimal Binary Search implementation of bisect_right:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def bisect_right(a, x, lo=0, hi=None, key=None):
    if lo < 0:
        raise ValueError('lo must be non-negative')
    if hi is None:
        hi = len(a)
    while lo < hi:
        mid = (lo + hi)//2
        if key is None:
            v = a[mid]
        else:
            v = key(a[mid])
        if a[mid] > x: 
            hi = mid
        else: 
            lo = mid + 1
    return lo
def bisect_right(a, x, lo=0, hi=None, key=None):
    if lo < 0:
        raise ValueError('lo must be non-negative')
    if hi is None:
        hi = len(a)
    while lo < hi:
        mid = (lo + hi)//2
        if key is None:
            v = a[mid]
        else:
            v = key(a[mid])
        if a[mid] > x: 
            hi = mid
        else: 
            lo = mid + 1
    return lo

–EOF (The Ultimate Computing & Technology Blog) —

GD Star Rating
loading...
626 words
Last Post: Teaching Kids Programming - Top Down and Bottom Up Dynamic Programming Algorithm to Type N letters on a 2-keys Keyboard
Next Post: Teaching Kids Programming - Greedy Algorithm to Find Longest Increasing Subsequence in O(NLogN) via Binary Search

The Permanent URL is: Teaching Kids Programming – Find Insertion Point in Sorted List via bisect_left or bisect_right

Leave a Reply