merge sort complexity on logn our recursive base case perform mergesort recursively on both halves merge each side together return mergeleft right arr copy changed no need to copy mutate inplace merge helper complexity on sort each one and place into the result add the left overs if there s any left to the result add the left overs if there s any left to the result return result return merged do not return anything as it is replacing inplace merge sort complexity o n log n our recursive base case perform merge_sort recursively on both halves merge each side together return merge left right arr copy changed no need to copy mutate inplace merge helper complexity o n sort each one and place into the result add the left overs if there s any left to the result add the left overs if there s any left to the result return result return merged do not return anything as it is replacing inplace
def merge_sort(arr):
    
    
    if len(arr) <= 1:
        return arr
    mid = len(arr) // 2
    
    left, right = merge_sort(arr[:mid]), merge_sort(arr[mid:])

    
    
    merge(left,right,arr)
    return arr


def merge(left, right, merged):
    

    left_cursor, right_cursor = 0, 0
    while left_cursor < len(left) and right_cursor < len(right):
        
        if left[left_cursor] <= right[right_cursor]:
            merged[left_cursor+right_cursor]=left[left_cursor]
            left_cursor += 1
        else:
            merged[left_cursor + right_cursor] = right[right_cursor]
            right_cursor += 1
    
    for left_cursor in range(left_cursor, len(left)):
        merged[left_cursor + right_cursor] = left[left_cursor]
    
    for right_cursor in range(right_cursor, len(right)):
        merged[left_cursor + right_cursor] = right[right_cursor]