【每日一题系列】--5.13

定义:对于数组A,如果存在下标 i < j 使得a[i] > a[j], 则称<a[i], a[j]>为一个逆序对。现对于一个给定的数组A,求其逆序对个数。

--------------------------------------------------------------------------------------------------

思路:
最简单的就是采用穷举法,利用两重循环来枚举数组中的每一个数对<a[i], a[j]>,然后检验 i < j时是否有a[i] > a[j],这样就可以统计逆序对的数目。但是这个方法的时间复杂度较大,达到O(n^2),当数组元素很大时效率很差。

较好的思路就是采用分治思想来讲数组进行排序,在排序的过程中统计每个子数组的逆序对个数:
我们将数组 A[start,...,end]的逆序对数量记为result(start, end).

问题分解:将数组分为尽量相等的两部分A[start,...,mid]和A[mid+1,...,end].其中mid=(start+end)/2,即以中间元素作为枢纽元分割数组。

子问题解决:分别递归求解子数组 A[start,...,mid]和A[mid+1,...,end],使这两个子数组以递增的形式排列。(排好序)

合并:如果逆序对中的两个数分别来自 A[start,...,mid]和A[mid+1,...,end]的话,那么这个逆序对就算入这两个子数组组成的数组的逆序对个数num,那么  result(start, end) =  result(start, mid) +  result(mid+1, end) + num.

现在问题的关键就在于如何快速地计算出两个子数组能够组成的逆序对个数num。

我们知道在计算出 result(start, mid) 后数组 A[start,...,mid]已经是排好序的了。因此在得到 result(start, mid)和 result(mid+1, end)时,我们同时得到已排好序的两个数组 A[start,...,mid]和A[mid+1,...,end]。此时我们考察分别来自 A[start,...,mid]和A[mid+1,...,end]的两个元素A[i]和A[j],若 A[i] >= A[j],那么 A[i]到 A[mid]中的每个数肯定比 A[j]要大,因此可以组成逆序对,这样的逆序对的个数为mid-i+1。 这样我们就可以只要遍历两个子数组一次就可以计算出 逆序对个数num。

统计部分的算法伪代码大致如下:

i = start;
j = mid + 1;
num = 0;

while(i <= med  && j <= end)
{
     if(A[i] >= A[j]){
          j++;
          num+=mid - i + 1;
     }else{
          i++;
     }
}


----------------------------------------------------------------------

代码实现:
Java版本:(由小红友情提供,若有任何bug请联系@ld_zhhj)

public class ReverseCouple {
	static int merge(int[]data, int start1, int start2, int end){
		int low = start1;
		int lowBound = start2 - 1;
		int high = start2;
		int highBound = end;
		int[]tempData = new int[end - start1 + 1];
		int count = 0;//累计逆序对
		int tempIndex = 0;
		while(low <= lowBound && high <= highBound){
			if(data[low] > data[high]){
				tempData[tempIndex++] = data[high++];
				count += lowBound - low + 1;//low~lowBound的数都大于high
			}else{
				tempData[tempIndex++] = data[low++];
			}
		}
		while(low <= lowBound){
			tempData[tempIndex++] = data[low++];
		}
		while(high <= highBound){
			tempData[tempIndex++] = data[high++];
		}
		for(int i = 0; i < tempData.length; i++){
			data[i + start1] = tempData[i];
		}
		return count;
	}
	static int mergeSort(int[]data, int low, int high){
		if(low < high){
			int mid = (low + high) / 2;
			int a = mergeSort(data, low, mid);
			int b = mergeSort(data, mid + 1, high);
			return a + b + merge(data, low, mid + 1, high);
		}
		return 0;
	}
	public static void main(String[]args){
		int[]data = {2,-1,5,6,0,2,4,3};
		printArray(data);
		System.out.println();
		System.out.println(mergeSort(data, 0, data.length - 1));
		printArray(data);
	}
	static void printArray(int[]data){
		for(int value : data){
			System.out.print(value + " , ");
		}
	}
}


你可能感兴趣的:(【每日一题系列】--5.13)