题目描述:数组排序
给定一个包含1-n的数列,我们通过交换任意两个元素给数列重新排序。求最少需要多少次交换,能把数组排成按1-n递增的顺序,其中,数组长度不超过100。
例如:
原数组是3,2,1, 我们只需要交换1和3就行了,交换次数为1,所以输出1。
原数组是2,3,1,我们需要交换2和1,变成1,3,2,再交换3和2,变为1,2,3,总共需要的交换次数为2,所以输出2。
函数头部:
C/C++
int run(const int *a,int n);
java
class solution {
public static int run(int [] a)
}
题目分析
刚看到这个题目的话,看起来很像是一个排序题,其实,我认为这也是一种解法,无非就是对给定的数组做一个类似选择排序的排序,每次将乱序部分最小的提到最前,即可满足条件,然后对其排序次数进行计数。但是这里需要注意的是,因为根据给定的函数原型来看,传入的是一个指向const的指针,所以需要重新new一个数组来对其进行一次拷贝再做。
上面的方法思路很简单,但是实际上浪费了空间,而且时间复杂度O(N^2)也比较高,所以还有优化空间,下面是我的思路:
思路很简单,我们只想知道需要多少次排序而不关心如何排序。首先,根据题意,N个数是1-N,即有序的等差数列,那么如果i正好排在了第i个数的位置,那么就无需再交换了,这实际上就是一个N阶置换。写个这样的例子:{3,4,1,5,2},可以看到,如果我们将1和3交换,那他们都已经在各自正确的位置了。那么剩下的呢?很简单,{4,5,2}他们又构成了一个循环置换,其实前面那样只有两个数{1,3}的也是一个循环置换,不过比较特别,只有两个数字,所以又叫对换。那么对于一个循环置换来说,需要几次交换才能排好序呢,想必大家也看出来了,就是阶数-1次,所以上面例子的答案就是 = (2-1)+(3-1) = 3。那么我们的思路就很简单了,只要把我们的置换,变为一些循环置换的乘积,问题就引刃而解了。
其实问题的求解远比我上面描述的要简单得多,上面这些只是我想介绍一些这个问题中的数学原理,其实可以证明,N阶置换可以唯一地表示为互不相交的循环置换的乘积。如果大家对这部分内容感兴趣的话,不妨看看抽象代数部分的知识。