剑指offer实践 ——51.数组中的逆序对(python版)



题目

数组中的逆序对
在这里插入图片描述


一、暴力遍历

暴力遍历数组,每遍历到一个数字,遍历其后面的所有数字,判断是否组成逆序对。
时间复杂度O(n^2)

def inverse_pari_1(arr):

    if not arr or len(arr) == 1:
        return 0
    res = 0
    for i in range(len(arr)):
        for j in range(i+1, len(arr)):
            if arr[i] > arr[j]:
                res += 1
    return res

二、分治归并

归并排序的思想

在【分】的时候,依旧每次分裂左右两部分
但【合】的时候,需要在调整顺序的同时,计算逆序对。
在这里插入图片描述
对于【7】,【5】这种情况,很明显能看到7的逆序对的贡献度为1,5的逆序对贡献度为0,和为1.

在【3,5,7】,【1,2,4】中:
假设有两个指针l_p、r_p分别指向left和right子数组的头部。
r_p指向的元素更小,放入res且r_p向右挪动一个指针指向2。

在这里插入图片描述
此时l_p指向3,r_p指向2,r_p指向的元素更小,放入res且r_p向右挪动一个指针指向4。
在这里插入图片描述
此时l_p指向3,r_p指向4,l_p指向的元素更小,放入res且累计逆序对的贡献度。r_p此时指向2,因此有2个元素(1,2)比左边的3更小,因此3在右边子数组的逆序对有2个。l_p向右挪动一个指针指向5。
在这里插入图片描述
此时l_p指向5,r_p指向4,r_p指向的元素更小,放入res且r_p向右挪动一个指针(此时指针为3,越界)结束遍历。
在这里插入图片描述
这个时候需要遍历指针未越界的list,在这里是左子数组。当左子数组剩下的数值都大于右子数组是,当前的5与右子数组组成的逆序对为右子数组的长度(【5,1】,【5,2】,【5,4】)

def inverse_pari_2(arr):
    if not arr:
        return 0
    if len(arr) == 1:
        return arr,0

    left = inverse_pari_2(arr[: (len(arr) // 2)])
    right = inverse_pari_2(arr[(len(arr) // 2):])

	r = merge(left[0], right[0])
    return r[0], r[1]+left[1]+right[1]


def merge(left, right):
    h, j, res, pairs = 0, 0, [], 0
    while h < len(left) and j < len(right):
        if left[h] > right[j]:
            res.append(right[j])
            j += 1
        else:
            res.append(left[h])
            pairs += j
            h += 1

    if h < len(left):
        for num in left[h:]:
            res.append(num)
            pairs += len(right)
    else:
        for num in right[j:]:
            res.append(num)
    return res, pairs

在这里插入图片描述
大神的更简洁高效的实现方法~~

    def mergeSort(nums, tmp, l, r):
        if l >= r:
            return 0

        mid = (l + r) // 2
        inv_count = mergeSort(nums, tmp, l, mid) + mergeSort(nums, tmp, mid + 1, r)
        i, j, pos = l, mid + 1, l
        while i <= mid and j <= r:
            if nums[i] <= nums[j]:
                tmp[pos] = nums[i]
                i += 1
                inv_count += (j - (mid + 1))
            else:
                tmp[pos] = nums[j]
                j += 1
            pos += 1
        for k in range(i, mid + 1):
            tmp[pos] = nums[k]
            inv_count += (j - (mid + 1))
            pos += 1
        for k in range(j, r + 1):
            tmp[pos] = nums[k]
            pos += 1
        nums[l:r+1] = tmp[l:r+1]
        return inv_count

    def reversePairs(nums):
        n = len(nums)
        tmp = [0] * n
        return mergeSort(nums, tmp, 0, n - 1)

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值