Search code examples
algorithmrecursiondivide-and-conquer

Does 'Divide and conquer' yield O(log N) for unsorted array?


Following algorithm finds max QAZ. QAZ of an element is number of elements with higher value after that element's index. The popular answer is to use divide and solve using O(nLog(n))..

The array is not sorted. In worst case 'Divide&Conquer' will touch all n elements. Also 'for loop' will touch n/2 elements at worse.. How is it n*log(n).. Shouldn't it be O(n^2).. thanks

class QAZ:
    def __init__(self, min, qaz):
        self.min = min
        self.qaz = qaz


def max_qaz(arr):
    n = len(arr)

    def max_qaz_util(start, end):
        if end <= start:
            return QAZ(arr[end], 0)
        elif start == (end + 1):
            return QAZ(arr[start], 1) if arr[start] < arr[end] else QAZ(arr[end], 0)
        mid = int((start + end) / 2)
        left = max_qaz_util(start, mid)
        right = max_qaz_util(mid + 1, end)
        if left.min < right.min:
            left.qaz += end - mid
            return left
        else:
            for i in range(mid + 1, end + 1):
                if arr[i] > left.min:
                    left.qaz += 1
        return left if left.qaz > right.qaz else right

    result = max_qaz_util(0, n - 1)
    print("minval", result.min)
    print("qaz", result.qaz)

max_qaz([33, 25, 26, 58, 41, 59])

Reference - https://shirleyisnotageek.blogspot.com/2015/02/find-maximum-qaz.html?showComment=1481295499335#c2817927984213209920


Solution

  • Yes, the for loop touches n/2 elements in the worst case. The important fact here is that the division of the input is as even as possible. The amount of work done by the algorithm on n elements is O(T(n)), where the recurrence T is defined by

    T(1) = O(1)
    T(n) = 2 T(n/2) + O(n).
    

    Case 2 of the Master Theorem applies, so T(n) = O(n log n). This is very similar to merge sort.