数组中的重要反转

时间:2014-11-04 21:50:17

标签: python arrays algorithm divide

我正在处理作业问题,以找出整数数组中重要反转的数量。 “显着倒置”定义如下:

  

排列中的显着倒置 [a 0 1 2 ,...,a n ] a i > 2 a j 对于某些 i< Ĵ。所以例如 a = [4,5,2,1,3] 恰好有3个显着的反转,因为对于这个排列 a 0 > 2a 3 1 > 2 a 2 1 > 2 a 3

解决方案需要 O(n log n)复杂性。这需要使用分而治之的方法。我选择基于合并排序来实现解决方案。

我理解这里给出的分裂操作:

def countInversions(list):
    if(len(list) <= 1):
        return list, 0
    else:
        mid = int(len(list)/2)
        left, a = countInversions(list[:mid])
        right, b = countInversions(list[mid:])
        result, c = mergeAndCount(left, right)
        return result, (a + b + c)

但是我遇到了merge and count方法的问题。具体计算重要倒数的数量。我通过计算正常的反转次数来调整我的代码。

def mergeAndCount(left, right):
    result = []
    count = 0
    i,j = 0,0
    while(i < len(left) and j < len(right)):
        if(left[i] > 2*right[j]):
            count += 1
        if(left[i] < right[j]):
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1

    while(left[i:] or right[j:]):
        if(left[i:]):
            if(left[i] > 2*right[j-1]):
                count += 1
            result.append(left[i])
            i += 1
        if(right[j:]):
            if(left[i-1] > 2*right[j]):
                count += 1
            result.append(right[j])
            j += 1
    return result, count

所以print(countInversions([4,5,2,1,3]))应该返回3.但是,它返回1.

我正在寻找关于合并和计数方法的一些指导。


最终实施:

def countInversions(list):
    if(len(list) <= 1):
        return list, 0
    else:
        mid = int(len(list)/2)
        left, a = countInversions(list[:mid])
        right, b = countInversions(list[mid:])
        result, c = mergeAndCount(left, right)
        return result, (a + b + c)

def mergeAndCount(left, right):
    result = []
    count = 0
    i,j = 0,0

    while(i < len(left) and j < len(right)):
        if(left[i] > 2*right[j]):
            count += len(left)-i
            j += 1
        else:
            i += 1

    i,j = 0,0
    while(i < len(left) and j < len(right)):
        if(left[i] < right[j]):
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1

    result.extend(left[i:])
    result.extend(right[j:])
    return result, count

1 个答案:

答案 0 :(得分:3)

你几乎就在那里,但有两个问题:

  1. 当您找到left[i] > 2*right[i]时,您的结论是left[i:]中的所有值都大于2*right[i],因此您应该将计数增加{{1}这与len(左)-i相同。 (你只是加上1就是为什么你的价值太低了。)

  2. 您需要将合并传递分为两个阶段,一个用于计算重要的反转,另一个用于生成已排序的输出数组。 (在正常的反转计数中,这两个会将i和j移动到相同的点,因此可以合并,但对于您的情况则不然。)

  3. 固定代码:

    len(left(i:])