• + 0 comments

    To put some tangible numbers behind this, I implemented the two functions that are O(3n) and O(n), then also added an implementation that should be much slower (but is also very readable and faster to implement) that is O(nlogn). The results are suprising:

    O(nlogn + 2n): 1.2469678640000001 O(3n): 1.1900847209999998 O(n): 1.2989587239999998

    The theoretically fastest solution is also the slowest of the group. I can think of a few microarchitectural reasons why that might be the case including a pair of floating point comparisons, but TLDR: always benchmark and regression test code that actually has to run fast. Don't rely on trivial Big-O analysis.

    #!/bin/python3
    
    import random
    import timeit
    import math
    
    def f(arr):
    	"""
    	O(nlogn + 2n)
    	"""
    	arr = sorted(arr)
    	return (sum(arr[0:4]),sum(arr[1:5]))
    
    def g(arr):
    	"""
    	O(3n)
    	"""
    	asum = sum(arr)
    	return (asum-(max(arr))), (asum-(min(arr)))
    
    def h(arr):
    	"""
    	O(n)
    	"""
    	amin = math.inf
    	amax = -math.inf
    	asum = 0
    	for a in arr:
    		if a < amin: amin = a
    		if a > amax: amax = a
    		asum += a
    	return (asum-amax,asum-amin)
    
    random.seed()
    arr = list(random.sample(range(10**9),5))
    
    print(timeit.timeit('f(arr)', globals=globals()))
    print(timeit.timeit('g(arr)', globals=globals()))
    print(timeit.timeit('h(arr)', globals=globals()))