You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求解使用1次任意交换与多次相邻交换对N的排列数组排序的最小交换次数

解决排列数组的最少交换次数问题

要解决这个问题,我们需要结合一次任意交换和任意多次相邻交换的特性,找到排序数组的最小总交换次数。核心思路是:要么直接用相邻交换排序(次数等于数组逆序数),要么先做一次最优任意交换,再用相邻交换排序(次数为1加上交换后的逆序数),最终取两者的最小值。

关键概念回顾

  • 逆序数:数组中满足i<j且arr[i]>arr[j]的元素对数量。相邻交换一次只能消除一个逆序对,因此仅用相邻交换排序的次数等于数组的逆序数。
  • 任意交换的价值:一次任意交换可以大幅减少后续需要的相邻交换次数,我们的目标是找到能让交换后逆序数最小的两个元素。

具体步骤

步骤1:计算原数组的逆序数

这是不使用任意交换时的总交换次数,可通过归并排序在O(N log N)时间内计算。

步骤2:枚举所有可能的交换对,计算交换后的逆序数

对于每一对元素(arr[i], arr[j])(i<j):

  1. 交换这两个元素得到新数组;
  2. 计算新数组的逆序数;
  3. 记录所有交换后的最小逆序数min_inv_after_swap。

步骤3:计算最终答案

最终答案是以下两种情况的最小值:

  • 不使用任意交换:original_inv(原逆序数);
  • 使用任意交换:1 + min_inv_after_swap(1次任意交换 + 交换后的相邻交换次数)。

示例验证

以数组{5,3,4,2,1}为例:

  1. 原逆序数计算:5比后面4个元素大,3比后面2个元素大,4比后面2个元素大,2比1个元素大,总逆序数为4+2+2+1=9;
  2. 交换5和1后,数组变为{1,3,4,2,5},新逆序数为2(3>2、4>2);
  3. 总次数对比:min(9, 1+2)=3,与示例结果一致。

代码实现(Python)

def count_inversions(arr):
    # 归并排序计算逆序数
    if len(arr) <= 1:
        return arr, 0
    mid = len(arr) // 2
    left, inv_left = count_inversions(arr[:mid])
    right, inv_right = count_inversions(arr[mid:])
    merged, inv_merge = merge(left, right)
    return merged, inv_left + inv_right + inv_merge

def merge(left, right):
    merged = []
    i = j = 0
    inv_count = 0
    while i < len(left) and j < len(right):
        if left[i] <= right[j]:
            merged.append(left[i])
            i += 1
        else:
            merged.append(right[j])
            j += 1
            inv_count += len(left) - i
    merged.extend(left[i:])
    merged.extend(right[j:])
    return merged, inv_count

def min_total_swaps(arr):
    n = len(arr)
    # 计算原逆序数
    _, original_inv = count_inversions(arr.copy())
    min_inv_after_swap = float('inf')
    
    # 暴力枚举所有交换对(适合n较小的场景)
    for i in range(n):
        for j in range(i+1, n):
            swapped = arr.copy()
            swapped[i], swapped[j] = swapped[j], swapped[i]
            _, inv = count_inversions(swapped)
            if inv < min_inv_after_swap:
                min_inv_after_swap = inv
    
    # 取两种方案的最小值
    option1 = original_inv
    option2 = 1 + min_inv_after_swap
    return min(option1, option2)

# 测试示例
arr = [5,3,4,2,1]
print(min_total_swaps(arr))  # 输出3

优化思路(针对大数据量)

上述暴力枚举的时间复杂度为O(N² log N),仅适合小N场景。对于大N(如1e5),可以通过树状数组预处理每个元素的统计量(左边比它大/小的元素数、右边比它大/小的元素数),在O(N log N)时间内快速计算交换任意两个元素后的逆序数变化,从而找到最优交换对。

内容的提问来源于stack exchange,提问作者unglinh279

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 18:03:15