Search code examples
python-3.xbinary-search

why bisect_left is faster than my implementation in python3


I am trying to solve this question and my implementation of binary search exceeds time limit. When I use bisect_left it runs faster and is accepted. Below is my approach.

def bs(self,new,k,n):
    st=0
    end=n
    while st<end:
        mid=(st+end)//2
        if new[mid]<k:
            st=mid+1
        else:
            end=mid
    return st
def smallerSum(self, n : int, arr : List[int],val) -> List[int]:
    new = sorted(arr)
    cum=[0 for _ in range(n+1)]
    for i in range(0,n):
        cum[i+1]=cum[i]+new[i]

    ans=[0 for _ in range(n)]
    for i in range(n):
        if val==0:
            ans[i] = cum[bisect_left(new,arr[i])]
        else:
            ans[i]= cum[self.bs(new,arr[i],n)]
    return ans

I tried to measure time for 10^5 random integers time taken by my implementation is around .33 seconds while bisect_left takes only 0.13 seconds. Complete code I used to measure time

from typing import List
from bisect import bisect_left,bisect_right
import random
import time
class Solution:
    def bs(self,new,k,n):
        st=0
        end=n
        while st<end:
            mid=(st+end)//2
            if new[mid]<k:
                st=mid+1
            else:
                end=mid
        return st
    def smallerSum(self, n : int, arr : List[int],val) -> List[int]:
        new = sorted(arr)
        cum=[0 for _ in range(n+1)]
        for i in range(0,n):
            cum[i+1]=cum[i]+new[i]

        ans=[0 for _ in range(n)]
        for i in range(n):
            if val==0:
                ans[i] = cum[bisect_left(new,arr[i])]
            else:
                ans[i]= cum[self.bs(new,arr[i],n)]
        return ans
if __name__=="__main__":
    n = 10**5
    arr=[]
    for i in range(n):
        arr.append(random.randint(0,10**9))
    obj = Solution()
    st=time.time()
    res = obj.smallerSum(n,arr,0)
    end=time.time()
    print(end-st)
    st=time.time()
    res = obj.smallerSum(n,arr,1)
    end=time.time()
    print(end-st)
    

Why there is such time difference and why bisect_left is faster?


Solution

  • As mentioned by @SuperStormer https://github.com/python/cpython/blob/7cb3a4474731f52c74b19dd3c99ca06e227dae3b/Lib/bisect.py#L72 python3 uses a faster C implementation which is why bisect_left takes lesser time.