演算法(5):求逆序數
阿新 • • 發佈:2020-12-30
我們從一道面試題入手開始
微軟面試題2010年:
在一個排列中,如果一對數的前後位置與大小順序相反,即前面的數大於後面的數,那麼它們就稱為一個逆序數對。
一個排列中逆序的總數就稱為這個排列的逆序數。如{2,4,3,1}中,2和1,4和3,4和1,3和1是逆序數對,
因此整個陣列的逆序數對個數為4,現在給定一陣列,要求統計出該陣列的逆序數對個數。
解:看到逆序數的次數有沒有想到我們常見的歸併排序呢,逆序數的求解本文的分享就是從歸併排序衍生出來的一種方法。
比如我們現在有兩個順序序列:
arr1[] = {1,3,5}
arr2[] = {2,2}
組成的序列位:1,3,5,2,2
當arr1[i] < arr2[j]時,看不出來是否存在逆序
但是當arr1[i] > arr2[j] ,則此時構成逆序對;
演算法實現時還有個點不能遺漏,比如arr2在合併排序中因為較小早早被合併進去,那arr1就會有剩餘的元素,剩餘的元素和原來的arr的每一個元素都構成逆序對
/*================================================================ * Copyright (C) 2020 baichao All rights reserved. * * 檔名稱:mergeSort.cpp * 創 建 者:baichao * 建立日期:2020年12月28日 * 描 述: * ================================================================*/ #include <iostream> int inverNumCount = 0; int sort(int *arr,int *temp,int start,int end) { if(start >= end) return -1; int k = start,len; int start1,end1,start2,end2; int mid = start + (end-start)/2; sort(arr,temp,start,mid); sort(arr,temp,mid+1,end); start1 = start; end1 = mid; start2 = mid +1; end2 = end; int flag = 0; while(start1 <= end1 || start2 <= end2) { if(start2>end2) { inverNumCount += (end-mid); flag = 1; temp[k++] = arr[start1++]; continue; } if(start1 > end1) { temp[k++] = arr[start2++]; continue; } if(arr[start1] <= arr[start2]) { temp[k++] = arr[start1++]; } else { temp[k++] = arr[start2++]; inverNumCount++; } } for(int i = start; i <= end; ++i) arr[i] = temp[i]; if(flag ==1) inverNumCount -= (end-mid); } int mergeSort(int *arr,int arr_size) { int temp[arr_size]; sort(arr,temp,0,arr_size - 1); std::cout<<inverNumCount<<std::endl; return 0; } int main() { int arr[] = {1,3,5,2,2}; mergeSort(arr,sizeof(arr)/sizeof(arr[0])); return 0; }
執行結果: