原题:
问题的关键是找到闭环。假设每个闭环有k个数字,则闭环内交换次数为k-1。最小交换次数为所有闭环内的交换次数相加。
闭环的含义是,从某个数字A1开始,若A1处于错误的index,则找到A2处于A1排序后的位置,找到A3处于A2排序后的位置......最后发现A1处于Ak排序后的位置。则A1,A2... Ak构成一个闭环。
举例说明 :
7 1 3 2 4 5 6 |
共有1个闭环,包含7 1 2 4 5 6,所以最小交换次数为6-1=5
2 3 1 5 6 4 8 9 7 |
共有3个闭环,分别为(2 3 1), (5 6 4), (8 9 7),所以最小交换次数为2+2+2=6
代码如下:
public class MinimumSwap2 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int[] arr = new int[n];
for(int i = 0; i < n; ++i) {
arr[i] = in.nextInt();
}
System.out.println(minimumSwaps(arr));
}
public static int minimumSwaps(int[] arr) {
Num[] ascArr = new Num[arr.length];
for(int i = 0; i < arr.length; ++i) {
ascArr[i] = new Num(i, arr[i]);
}
Arrays.sort(ascArr, new Comparator<Num>() {
@Override
public int compare(Num o1, Num o2) {
return o1.value - o2.value;
}
});
int[]visited = new int[arr.length];
int i = 0;
int res = 0;
int count = 0;
while(true) {
if(count > 0) {
res += (count - 1);
count = 0;
}
int j = 0;
for(; j < visited.length; ++j) {
if(visited[j] == 0) {
if(arr[j] == ascArr[j].value) {
visited[j] = 1;
} else {
i = j;
break;
}
}
}
if(j >= visited.length) {
break;
}
//找到某个闭环
while(i < arr.length && visited[i] == 0) {
if(arr[i] != ascArr[i].value) {
visited[i] = 1;
i = ascArr[i].ori;
++count;
}
}
}
return res;
}
static class Num {
int ori;
int value;
Num(int index, int val) {
ori = index;
value = val;
}
}
}