《算法导论》第二章思考题——逆序对(python实现)

       设A[1..n]是一个包含n个不同数的数组。如果在i < j的情况下,有A[i] > A[j],则(i, j)就称为A中的一个逆序对,给出任意一个数组,计算逆序对个数。借助归并排序思想可以得到O(n log n)的最坏运行时间。

       归并排序的想法是先分开左右 两个子序,每个子序列排序后再合并。这里求逆序对也是一样,分开后先计算每个子序内部的逆序对数量并将其从大到小进行排列,在合并时,计算子序之间的逆序对。

       假定在某步需要合并两个有序的子序列A=[a1,a2,a3……]和B=[b1.b2,b3……],已经统计出A,B子序内部的逆序对分别为A_cont,B_cont,并设置一个序列记录合并排序结果。

        首先比较a1和b1,如果a1>b1,说明a1可以和B中所有的元素都构成逆序对(A,B倒序排列),逆序对增加B元素个数,将a1弹出加入结果列表,A指针后移;如果a1<=b1,说明b1大于A中所有元素,因此b1与A中元素无法构成逆序对,逆序对个数不增加,将b1弹出加入结果列表,B指针后移……直到其中一个列表为空,这时需要分析一下,因为一个列表已经为空了,另一个列表无论是A还是B中的元素都无法与它构成数对了,且剩余元素为两列表最小的元素,因此只需要直接将直接加到结果序列后面即可。
       这里先给出代码,再举例解释运行过程。

def merge_count(list):
    if len(list) <= 1:
        return list, 0
    mid = len(list) // 2
    left_li,left_cont = merge_count(list[:mid])
    right_li,right_cont = merge_count(list[mid:])
    count = left_cont + right_cont

    left_p, right_p = 0, 0
    result = []
    while left_p < len(left_li) and right_p < len(right_li):
        if left_li[left_p] > right_li[right_p]:
            result.append(left_li[left_p])
            count += len(right_li[right_p:])
            left_p += 1
        else:
            result.append(right_li[right_p])
            right_p += 1
    result += left_li[left_p:]
    result += right_li[right_p:]
    return result, count


if __name__ == "__main__":
    mylist = [5, 2, 4, 3, 1]
    print("-" * 50)
    _, count = merge_count(mylist)
    print(count)

   举例来说:mylist=[2,5, 4, 3, 1]

《算法导论》第二章思考题——逆序对(python实现)_第1张图片

《算法导论》第二章思考题——逆序对(python实现)_第2张图片

看了网上的代码,做了如下修改,运行结果相同:

def merge_count_2(list):
    if len(list) <= 1:
        return list, 0
    mid = len(list) // 2
    left_li,left_cont = merge_count(list[:mid])
    right_li,right_cont = merge_count(list[mid:])
    count = left_cont + right_cont


    result = []
    while 0 < len(left_li) and 0 < len(right_li):
        if left_li[0] > right_li[0]:
            result.append(left_li.pop(0))
            count += len(right_li)
        else:
            result.append(right_li.pop(0))
    result += left_li
    result += right_li
    return result, count

 

你可能感兴趣的:(算法)