Python学习笔记12-算法:求数组中的逆序对

逆序对(Inversion Pair)是指在数组中,两个元素的位置满足前面的元素比后面的元素大。例如,对于数组 [2, 3, 8, 6, 1],逆序对是 (2, 1)(3, 1)(8, 6)(8, 1)

方法

1. 暴力法

暴力法是最直接的方法,通过两层循环来计算逆序对。虽然实现简单,但其时间复杂度为 O(n^2),对于大规模数据不够高效。

def count_inversions_brute_force(arr):
    n = len(arr)
    count = 0
    for i in range(n):
        for j in range(i + 1, n):
            if arr[i] > arr[j]:
                count += 1
    return count

# 使用示例
arr = [2, 3, 8, 6, 1]
print(count_inversions_brute_force(arr))  # 输出: 5
2. 使用归并排序(Merge Sort)

利用归并排序计算逆序对可以显著提高效率。归并排序在排序的过程中可以同时计算逆序对,其时间复杂度为 O(n log n)

代码实现
def merge_count_split_inv(arr, temp_arr, left, mid, right):
    i = left    # 起始位置左半部分
    j = mid + 1 # 起始位置右半部分
    k = left    # 起始位置临时数组
    inv_count = 0
    
    # 合并两部分
    while i <= mid and j <= right:
        if arr[i] <= arr[j]:
            temp_arr[k] = arr[i]
            i += 1
        else:
            temp_arr[k] = arr[j]
            inv_count += (mid-i + 1)
            j += 1
        k += 1
    
    # 复制剩余元素
    while i <= mid:
        temp_arr[k] = arr[i]
        i += 1
        k += 1
    
    while j <= right:
        temp_arr[k] = arr[j]
        j += 1
        k += 1
    
    for i in range(left, right + 1):
        arr[i] = temp_arr[i]
        
    return inv_count

def merge_sort_and_count(arr, temp_arr, left, right):
    inv_count = 0
    if left < right:
        mid = (left + right)//2
        
        inv_count += merge_sort_and_count(arr, temp_arr, left, mid)
        inv_count += merge_sort_and_count(arr, temp_arr, mid + 1, right)
        inv_count += merge_count_split_inv(arr, temp_arr, left, mid, right)
    
    return inv_count

def count_inversions(arr):
    temp_arr = [0]*len(arr)
    return merge_sort_and_count(arr, temp_arr, 0, len(arr) - 1)

# 使用示例
arr = [2, 3, 8, 6, 1]
print(count_inversions(arr))  # 输出: 5

解释

  1. 归并排序和逆序对计数

    • 分割:将数组递归地分成两半,直到每部分只有一个元素。
    • 合并:在合并两个有序子数组时,计算逆序对。对于左半部分的每一个元素,如果它大于右半部分的元素,说明存在逆序对。
  2. merge_count_split_inv函数

    • 负责合并两个有序子数组并计算逆序对。
    • 当发现左半部分的元素大于右半部分的元素时,计算逆序对的数量并更新逆序对计数。

时间复杂度

  • 暴力法O(n^2)
  • 归并排序O(n log n),由于分治的递归和合并过程中对逆序对的计算。

归并排序方法更加高效,适用于大规模数据集,并且通过利用排序过程来计算逆序对。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值