Codility每周一课:P99.4 ArrayInversionCount

版权声明:AnFany https://blog.csdn.net/qq_32882309/article/details/88715363

0.png

P99.4 ArrayInversionCount
Compute number of inversion in an array.

  • P99.4 逆序索引对
    计算数组中的逆序索引对的数量

给出一个由N个整数组成的数组A。索引对(P,Q)是逆序的,如果P<Q,并且A[Q] < A[P]。

编写函数:

def solution(A)

计算A中的逆序索引对的数量,如果它超过1,000,000,000,则返回−1。

例如,对于数组A:A[0]=-1,A[1]=6,A[2]=3,A[3]=4,A[4]=7,A[5]=4。有4个逆序索引对:(1,2)(1,3)(1,5)(4,5),函数应该返回4。

假定:

  1. N是区间[0,100,000]内的整数;
  2. 数组A的每个元素都是区间-2,147,483,648,2,147,483,647]内的整数;
  • 解题思路

直接计算的时间复杂度为O(N**2),显然不可取。数组是无序的,因此考虑利用排序算法解决此问题,也就是在排序过程中计算逆序索引对的个数。现在说明利用归并排序解决此问题。

归并排序就是将数组A分左、右两部分。最终的逆序索引对的个数就等于左部分的逆序索引对的个数、右部分的逆序索引对的个数与合并左右2部分得到的逆序索引对之和。但归根结底这个逆序索引对的个数都是通过合并已经排好序的左右2部分得到的。

下面给出合并已经排好序的左右两部分的逆序索引对的计算过程:

假设A=[3, 11, 8, 10, 3],开始分为2部分AL= [3, 11, 8] 和 AR= [10, 3],排序后分别是SL=[3, 8, 11] 和SR= [3, 10]。最终合并后的序列为K。

  1. SL[0]=3和SR[0]=3。前者不大于后者,不存在逆序索引对;SL删除索引为0的元素。SL=[8, 11] ,K添加被删除的元素K=[3];

  2. SL[0]=8和SR[0]=3。前者大于,因此存在逆序索引对,并且8之后的元素都是逆序索引对,也就是有2个。SR删除索引为0的元素。SR=[10],K添加被删除的元素K=[3, 3];

  3. SL[0]=8和SR[0]=10。前者不大于,因此不存在逆序索引对,SL删除索引为0的元素。SL=[11] ,K添加被删除的元素K=[3, 3, 8];

  4. SL[0]=11和SR[0]=10。前者大于,因此存在逆序索引对,因为SL只有这一个元素了,因此逆序索引数为1个。SR删除索引为0的元素。SL=[] ,K添加被删除的元素K=[3, 3, 8, 10];

  5. 左右有一个为空就停止判断。最后K添加SL剩余的元素K=[3, 3, 8, 10, 11],结束;

也就是说从[3, 8, 11, 3, 10]变为[3, 3, 8, 10, 11]一共有3个逆序索引数对。 同理可得到[3, 11, 8]变为[3, 8, 11]有1个, [10, 3]变为[3, 10]也有1个。因此一共5个。

  • Python3代码
# -*- coding:utf-8 -*-
# &Author  AnFany
# Lesson 99:Future training
# P 99.4 ArrayInversionCount


def solution_direct(A):
    """
    返回数组A中逆序索引对的个数
    时间复杂度O(N**2)
    :param A: 数组
    :return: 逆序索引对的个数
    """
    return len([0 for i in range(len(A)) for j in range(i, len(A)) if A[i] > A[j]])


def merge(a):
    """
    实现归并排序
    :param a:数组
    :return:逆序索引对的个数
    """
    # 总的逆序索引对的个数
    length = len(a)
    if length <= 1:
        return a, 0
    # 分割点
    middle = length // 2
    # 左边
    left_list, left_count = merge(a[: middle])
    # 右边
    right_list, right_count = merge(a[middle:])
    # 左右之和
    count = left_count + right_count
    # 合并在一起的序列,也就是排序后的系列
    sorted_list = []
    #  合并时候的逆序数
    while len(left_list) and len(right_list):
        if left_list[0] > right_list[0]:
            len_left = len(left_list)
            count += len_left
            small = right_list.pop(0)
            sorted_list.append(small)
        else:
            small = left_list.pop(0)
            sorted_list.append(small)

    if left_list:
        sorted_list += left_list
    else:
        sorted_list += right_list
    return sorted_list, count


def solution(A):
    """
    返回数组A中逆序索引对的个数
    利用归并排序的思想,最终的逆序数对的个数=左序列排完序得到的逆序数+右序列排完序得到的逆序数+合并左右得到的逆序数
    其实所有的逆序数归根结底都是合并左右得来的逆序数
    时间复杂度:O(N*log(N))
    :param A: 数组
    :return: 逆序索引对的个数
    """
    length = len(A)
    if length <= 1:
        return 0
    count = merge(A)[1]
    if count > 1e9:
        return -1
    return count
  • 结果

image

点击获得更多编程练习题。欢迎Follow,感谢Star!!! 扫描关注微信公众号pythonfan,获取更多。

image

image

猜你喜欢

转载自blog.csdn.net/qq_32882309/article/details/88715363