1. 程式人生 > >HackerRank- Minimum Swap 2 陣列排序最小交換次數

HackerRank- Minimum Swap 2 陣列排序最小交換次數

原題:

問題的關鍵是找到閉環。假設每個閉環有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;
		}
	}
}