算法之路_7、逆序对问题

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/SIMPLE1995/article/details/86515108

一、问题

在一个数组中,左边的数如果比右边的数大,则折两个数构成一个逆序对,请打印所有逆序对。

二、解析

如果前一篇小和问题能够理解,那么这个逆序对问题也就可以迎刃而解了。两个问题其实差不多,只不过换了种说法。

三、代码

package algorithm;
/*
 *2019年1月11日
 */

public class Code_Inverse {
	
	public static int res = 0;
	
	public static void mergeSort(int[] arr) {
		if (arr == null || arr.length < 2) {
			return;
		}
		codeInverse(arr, 0, arr.length - 1);
	}
 
	private static void codeInverse(int[] arr, int l, int r) {
		if (l == r) {
			return;
		}
		int mid = l + ((r - l) >> 1);
		codeInverse(arr, l, mid);
		codeInverse(arr, mid + 1, r);
		merge(arr, l, mid, r);
	}
 
	private static void merge(int[] arr, int l, int mid, int r) {
		int[] help = new int[r - l + 1];
		int p1 = l;
		int p2 = mid + 1;
		int i = 0;
		
		while (p1 <= mid && p2 <= r) {
			//若左边区域所指向数字大于右边区域所指向数字 则两者构成逆序对 打印之
			if (arr[p1] > arr[p2]) {
				//统计逆序对个数 因为左右皆有序 所以当出现一个大于左边所指数字时 右边数字后面所有数字皆可构成逆序对
				res += mid - p1 + 1;	
				for(int j = p1; j<= mid ; j++){
					System.out.print(arr[j] + " " + arr[p2] + "|");//打印逆序对
				}
			}
			//常规归并操作 不理解参考归并排序一文
			help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
		}
		while (p1 <= mid) {
			help[i++] = arr[p1++];
		}
		while (p2 <= r) {
			help[i++] = arr[p2++];
		}
		for (i = 0; i < help.length; i++) {
			arr[l + i] = help[i];
		}
	}
 
	// for test
	public static void main(String[] args) {
		int[] test = {3,1,5,0,2,3};
		mergeSort(test);
		System.out.println("逆序对的个数:"+ res);
	}
 
}

四、补充

大家如果也看了前面的博文,大致可以看到算法之路从0起步,并且一文套一文。 大家应该也发现了归并排序,小和问题,包括本文逆序对问题。三个问题代码基本一模一样。对,这就是相同类似思想问题的同一种解决方案,算法并不是固定的求解问题,而是求解一类问题。这三个问题可以通过分治思想来做,只有过最后所求不同。希望像我一样初学算法的同学也可以从中有所体会。

猜你喜欢

转载自blog.csdn.net/SIMPLE1995/article/details/86515108
今日推荐