1. 程式人生 > >白話經典算法系列之九 從歸併排序到數列的逆序數對(微軟筆試題)

白話經典算法系列之九 從歸併排序到數列的逆序數對(微軟筆試題)

首先來看看原題

 

微軟2010年筆試題

在一個排列中,如果一對數的前後位置與大小順序相反,即前面的數大於後面的數,那麼它們就稱為一個逆序數對。一個排列中逆序的總數就稱為這個排列的逆序數。如{2,4,3,1}中,2和1,4和3,4和1,3和1是逆序數對,因此整個陣列的逆序數對個數為4,現在給定一陣列,要求統計出該陣列的逆序數對個數。

 

計算數列的逆序數對個數最簡單的方便就最從前向後依次統計每個數字與它後面的數字是否能組成逆序數對。程式碼如下:

#include <stdio.h>
int main()
{
	printf("     數列的逆序數對 \n"
); printf(" -- by MoreWindows( http://blog.csdn.net/MoreWindows ) --\n\n"); const int MAXN = 8; int a[MAXN] = {1, 7, 2, 9, 6, 4, 5, 3}; int nCount = 0; int i, j; for (i = 0; i < MAXN; i++) for (j = i + 1; j < MAXN; j++) if (a[i] > a[j]) nCount++; printf("逆序數對為: %d\n", nCount); }

執行結果如下:

這種方法用到了雙迴圈,時間複雜度為O(N^2),是一個不太優雅的方法。因此我們嘗試用其它方法來解決。

 

在《白話經典算法系列之五歸併排序的實現》中觀察歸併排序——合併數列(135)(24)的時候:

1.先取出前面數列中的1

2.然後取出後面數列中的2明顯!這個2和前面的35都可以組成逆序數對即3252都是逆序數對。

3.然後取出前面數列中的3

4.然後取出後面數列中的4同理,可知這個4和前面數列中的5可以組成一個逆序數對。

這樣就完成了逆序數對的統計,歸併排序的時間複雜度是O(N * LogN),因此這種從歸併排序到數列的逆序數對的解法的時間複雜度同樣是O(N * LogN),下面給出程式碼:

//從歸併排序到數列的逆序數對
#include <stdio.h>
int g_nCount;
void mergearray(int a[], int first, int mid, int last, int temp[])
{
	int i = first, j = mid + 1;
	int m = mid,   n = last;
	int k = 0;

	while (i <= m && j <= n) //a[i] 前面的數  a[j] 後面的數
	{
		if (a[i] < a[j])
			temp[k++] = a[i++];
		else
		{
			temp[k++] = a[j++];
			//a[j]和前面每一個數都能組成逆序數對
			g_nCount += m - i + 1;
		}
	}

	while (i <= m)
		temp[k++] = a[i++];

	while (j <= n)
		temp[k++] = a[j++];

	for (i = 0; i < k; i++)
		a[first + i] = temp[i];
}
void mergesort(int a[], int first, int last, int temp[])
{
	if (first < last)
	{
		int mid = (first + last) / 2;
		mergesort(a, first, mid, temp);    //左邊有序
		mergesort(a, mid + 1, last, temp); //右邊有序
		mergearray(a, first, mid, last, temp); //再將二個有序數列合併
	}
}

bool MergeSort(int a[], int n)
{
	int *p = new int[n];
	if (p == NULL)
		return false;
	mergesort(a, 0, n - 1, p);
	return true;
}

int main()
{
	printf("     從歸併排序到數列的逆序數對 \n");    
	printf(" -- by MoreWindows( http://blog.csdn.net/MoreWindows ) --\n\n");    

	const int MAXN = 8;
	int a[MAXN] = {1, 7, 2, 9, 6, 4, 5, 3};

	g_nCount = 0;
	MergeSort(a, MAXN);
	printf("逆序數對為: %d\n", g_nCount);
	return 0;
}

執行結果:

 

 

好了,介紹到這裡後,相信大家對如何求數列的逆序數對已經有了很好的認識,文章中所用到的“知識遷移”這種方法還是不錯的,值得大家掌握。

 

 

轉載請標明出處,原文地址:http://blog.csdn.net/morewindows/article/details/8029996

再分享一下我老師大神的人工智慧教程吧。零基礎!通俗易懂!風趣幽默!還帶黃段子!希望你也加入到我們人工智慧的隊伍中來!https://www.cnblogs.com/captainbed