排序算法之:最小交换次数排序(Minimum Swaps to Sort)的图论模型与环分解优化
字数 1332 2025-11-30 06:17:20
排序算法之:最小交换次数排序(Minimum Swaps to Sort)的图论模型与环分解优化
题目描述
给定一个包含 n 个不同整数的数组 arr,数组中的元素是 0 到 n-1 的任意排列。要求通过交换任意两个元素的位置,将数组升序排列,求所需的最小交换次数。例如:
输入:arr = [4, 3, 2, 1, 0]
输出:2(交换过程可能为:交换索引0和4→[0,3,2,1,4],再交换索引1和3→[0,1,2,3,4])。
解题过程
1. 问题分析
- 直接通过排序算法(如快速排序)只能得到排序结果,但无法记录最小交换次数。
- 关键观察:若元素已排序,则元素
i应位于索引i处。交换操作的本质是将元素移动到其正确位置。 - 目标:通过最少的交换次数,使每个元素回到其目标位置(即
arr[i] = i)。
2. 图论建模
-
将数组视为一个置换(Permutation),并构建一个有向图:
- 节点:数组的索引
0到n-1。 - 边:从节点
i指向节点arr[i](表示当前位于i的元素应去往位置arr[i])。
- 节点:数组的索引
-
例如
arr = [4, 3, 2, 1, 0]的边为:
0→4, 1→3, 2→2, 3→1, 4→0。 -
性质:由于每个节点出度和入度均为1,图由若干不相交的环组成。
- 自环(如
2→2)表示元素已在正确位置,无需交换。 - 每个长度为
k的环需要k-1次交换才能将环内所有元素归位。
- 自环(如
3. 最小交换次数公式
- 设图中有
c个环(包括自环),每个环的长度为l₁, l₂, ..., l_c。 - 总交换次数 =
(l₁ - 1) + (l₂ - 1) + ... + (l_c - 1) = n - c。 - 推导:每次交换可减少一个环(例如交换环中两个元素可将环拆分为两个),最终需要
n个自环,而初始有c个环,故需n - c次交换。
4. 算法步骤
- 遍历数组,构建并检测环的数量:
- 用
visited数组标记已访问的索引。 - 从索引
i开始,沿边i → arr[i]遍历,直到回到起点,记录一个环。
- 用
- 统计所有环的数量
c(包括自环)。 - 返回
n - c。
示例计算
arr = [4, 3, 2, 1, 0]:
- 环1:
0 → 4 → 0(长度2) - 环2:
1 → 3 → 1(长度2) - 环3:
2 → 2(自环,长度1)
环数c = 3,交换次数 =5 - 3 = 2。
5. 代码实现(Python)
def min_swaps(arr):
n = len(arr)
visited = [False] * n
cycles = 0
for i in range(n):
if not visited[i] and arr[i] != i:
cycles += 1
current = i
while not visited[current]:
visited[current] = True
current = arr[current] # 移动到下一个节点
return n - cycles
# 测试
arr = [4, 3, 2, 1, 0]
print(min_swaps(arr)) # 输出 2
6. 复杂度分析
- 时间复杂度:
O(n),每个节点仅被访问一次。 - 空间复杂度:
O(n),用于记录访问状态。
7. 扩展:处理重复元素
若数组包含重复元素,上述方法失效(因置换图模型要求元素唯一)。此时需改用其他策略,如转化为最小交换次数使相邻元素有序问题(较复杂,需另讨论)。
总结
通过将置换分解为环,最小交换次数问题被转化为图论中的环计数问题,利用 n - c 公式高效求解。该方法高效且直观,体现了排序问题与图论的深刻联系。