面试题36:数组中的逆序对(归并排序思想)
在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。例如,有一个数组为Array[0..n] 其中有元素a[i],a[j].如果 当i<j时,a[i]>a[j],那么我们就称(a[i],a[j])为一个逆序对。在数组{7,5,6,4}中一共存在5对逆序对,分别是(7,6),(7,5),(7,4),(6,4),(5,4)。
最简单的想法就是遍历每一个元素,让其与后面的元素对比,如果大于则count++,但是这样的时间复杂度是o(n2)。这题有更好的解决方法,时间复杂度只需要o(nlogn)。其实这道题目的思路跟归并排序差不多,求逆序对的过程就是一个求归并排序的过程,在求出逆序对以后,原数组变得有序,是通过归并排序得到的。
代码中31行之后相当于归并排序的Merge函数,作用是求两个归并序列归并后存在的逆序对
1 int InversePairsCore(int* data, int* copy, int start, int end); 2 3 int InversePairs(int* data, int length) 4 { 5 if(data == NULL || length < 0) 6 return 0; 7 8 int* copy = new int[length]; 9 for(int i = 0; i < length; ++ i) 10 copy[i] = data[i]; 11 12 int count = InversePairsCore(data, copy, 0, length - 1); 13 delete[] copy; 14 15 return count; 16 } 17 18 int InversePairsCore(int* data, int* copy, int start, int end) 19 { 20 if(start == end) 21 { 22 copy[start] = data[start]; 23 return 0; 24 } 25 26 int length = (end - start) / 2; 27 28 int left = InversePairsCore(copy, data, start, start + length); 29 int right = InversePairsCore(copy, data, start + length + 1, end); 30 31 // i初始化为前半段最后一个数字的下标 32 int i = start + length; 33 // j初始化为后半段最后一个数字的下标 34 int j = end; 35 int indexCopy = end; 36 int count = 0; 37 while(i >= start && j >= start + length + 1) 38 { 39 if(data[i] > data[j]) 40 { 41 copy[indexCopy--] = data[i--]; 42 count += j - start - length; 43 } 44 else 45 { 46 copy[indexCopy--] = data[j--]; 47 } 48 } 49 50 for(; i >= start; --i) 51 copy[indexCopy--] = data[i]; 52 53 for(; j >= start + length + 1; --j) 54 copy[indexCopy--] = data[j]; 55 56 return left + right + count; 57 }