求逆序数对个数(微软2010年笔试题)

题目:

在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序数对。一个排列中逆序的总数就称为这个排列的逆序数。如{2,4,3,1}中,2和1,4和3,4和1,3和1是逆序数对,因此整个数组的逆序数对个数为4,现在给定一数组,要求统计出该数组的逆序数对个数。

解法一:冒泡法

类似于冒泡排序,假设数组长度为n,设置一个计数count,从i=0到i=n-1进行遍历,如果符合逆序数对条件,则将count加1。代码如下:

public static void main(String[] args) {
		int[] array = {2,4,3,1};
		int count = method(array);
		System.out.println("逆序数对个数为:" + count);
	}

其中method方法为:

private static int method(int[] array) {
		int count = 0;
		for(int i=0; i array[j]) {
					count++;
				}
			}
		}
		return count;
	}

最后输出结果为:

逆序数对个数为:4

不难看出,该算法的时间复杂度为0(n^2)。



解法二:归并法

举例说明,有如下两个数组,{1,3,5}和{2,4},采用归并排序步骤如下:

(1)取出第一个数组中的1.

(2)取出第二个数组中的2,此时2与第一个数组中的3和5可以构成逆序数对。

(3)取出第一个数组中的3.

(4)取出第二个数组中的4,此时4与第一个数组中的5可以构成逆序数对。

从上面的分析不难看出,可以用类似于归并排序算法来计算逆序数对的个数。归并排序的时间复杂度为O(nlogn),因此该方法求取逆序数对个数的时间复杂度也为O(nlogn)。

代码如下:

定义计数的成员变量:

private static int count = 0;

归并方法定义为:

private static void mergeMethod(int[] array) {
		int[] temp = new int[array.length];
		mergeSort(array, 0, array.length - 1, temp);
	}

递归代码:

private static void mergeSort(int[] array, int first, int last, int[] temp) {
		if(first < last) {
			int mid = (last + first) / 2;
			mergeSort(array, first, mid, temp);
			mergeSort(array, mid + 1, last, temp);
			mergeArray(array, first, mid, last, temp);
		}
	}

数组合并代码:

private static void mergeArray(int[] array, int first, int mid, int last,
			int[] temp) {
		int i = first, m = mid;
		int j = mid + 1, n = last;
		int k = 0;
		while(i <= m && j <= n) {
			if(array[i] < array[j]) {
				temp[k++] = array[i++];
			}
			else {
				temp[k++] = array[j++];
				count += m - i + 1;
			}
		}
		while(i <= m) {
			temp[k++] = array[i++];
		}
		while(j <= n) {
			temp[k++] = array[j++];
		}
		for(i=0; i

输出结果为:

逆序数对个数为:4

你可能感兴趣的:(算法分析,面试题)