排序算法之:最小交换次数排序(Minimum Swaps to Sort)的进阶应用:图论模型与环分解优化(深度版)
题目描述
给定一个由 n 个不同整数 构成的数组 arr,元素取值范围为 1 到 n。每次允许交换任意两个元素。目标是求出将数组按升序排列所需的 最小交换次数。
示例
输入:arr = [4, 3, 1, 2]
输出:3
解释:
- 交换索引0和2 →
[1, 3, 4, 2] - 交换索引1和3 →
[1, 2, 4, 3] - 交换索引2和3 →
[1, 2, 3, 4],共3次交换。
解题过程
最小交换次数问题可以通过 图论模型 高效解决。关键在于将数组排序转化为 循环分解,并通过环的大小计算交换次数。
第一步:将数组映射为有向图
由于数组元素是 1 到 n 的不同整数,我们可以将数组视为一个 置换(permutation)。
定义映射:
- 当前位置
i(索引从0开始)存放的元素值是arr[i]。 - 这个元素的 目标位置 应为
arr[i] - 1(因为排序后值k应在索引k-1处)。
构建有向图:
- 节点:数组的
n个位置(索引0到n-1)。 - 有向边:从
i指向arr[i] - 1。
这表示当前位于位置i的元素应该被移动到位置arr[i] - 1才能到达其最终排序位置。
以 arr = [4, 3, 1, 2] 为例:
- 位置0(值4)应去位置3(因为排序后值4应在索引3)。
- 位置1(值3)应去位置2。
- 位置2(值1)应去位置0。
- 位置3(值2)应去位置1。
边集合:0 → 3,1 → 2,2 → 0,3 → 1。
第二步:识别图中的环
在有向图中,由于每个节点有且仅有一条出边和一条入边(因为每个位置对应唯一的目标位置),图会分解为若干个 不相交的有向环。
用示例说明:
从节点0出发:0 → 3 → 1 → 2 → 0,形成一个长度为4的环。
(实际上,这个置换只有一个环,包含所有4个节点。)
为什么是环?
因为如果你从某个位置出发,沿着“当前元素的目标位置”一直走,最终会回到起点(路径不会终止,且不会分叉)。这正好构成了一个循环。
第三步:用环计算最小交换次数
关键定理:对于一个长度为 cycle_len 的环,将其中的所有元素归位到正确位置所需的最小交换次数是 cycle_len - 1。
解释:
- 在一个环中,每次交换可以将一个元素放到正确位置,同时将另一个元素移动到环中的下一个位置。
- 经过
cycle_len - 1次交换,环中所有元素都归位。 - 例如,一个长度为1的环(自环)表示该元素已经在正确位置,交换次数为0。
因此,总的最小交换次数 = 所有环的 (cycle_len - 1) 之和。
等价地,设图中有 C 个环,则:
总交换次数 = n - C
(因为每个环贡献 cycle_len - 1,所有环的长度之和为 n,所以总和 = n - C)。
示例验证:
- 示例中只有一个环,长度
cycle_len = 4,C = 1。 - 最小交换次数 =
4 - 1 = 3,与前面一致。
第四步:算法实现
我们可以在 O(n) 时间和 O(1) 额外空间内完成环的检测和计数,不需要显式建图。
具体步骤:
- 创建一个
visited数组(或原地标记)来记录位置是否已被处理。 - 遍历每个位置
i:- 如果
i已被访问,或arr[i]已在正确位置(即arr[i] == i+1),则跳过。 - 否则,从
i开始沿着“目标位置”追踪环:- 初始化
cycle_len = 0,current = i。 - 当
current未被访问时:- 标记
current为已访问。 - 将
current移动到其目标位置:current = arr[current] - 1。 cycle_len++。
- 标记
- 此环对交换次数的贡献为
cycle_len - 1,累加到总结果中。
- 初始化
- 如果
- 返回总交换次数。
优化:可以原地修改数组来标记访问,例如将访问过的位置元素取负数(如果允许修改原数组且元素为正)。
第五步:正确性证明
- 每次交换可以将一个环的长度减少1(即让一个元素归位),直到整个环被解决。
- 对于一个长度为
k的环,至少需要k-1次交换(因为最后一次交换会让两个元素同时归位)。 - 该算法通过追踪环结构,精确计算了这个下界,因此结果是最优的。
第六步:扩展与变体
- 包含重复元素的情况:此时图可能不再是简单环,而需要更复杂的处理(例如通过贪心或并查集)。
- 最小交换次数使相邻交换:如果只允许交换相邻元素,则转化为逆序对计数问题。
- 最小交换次数使数组有序(元素可重复):可通过比较排序后的数组与原始数组,计算环的分解。
总结
将数组排序的最小交换次数问题,通过建立 位置-目标位置 的映射,转化为有向图的环分解。最小交换次数等于 n - C,其中 C 是图中环的数量。这个基于图论模型的方法高效、优雅,且提供了对置换排序的深刻理解。