面试题 36(*),数组中的逆序对(类似归并排序,不过归并时添加计数器记录逆序对的数量)

思路:如果用O(n^2)自然可以完成。我并没有想到比较好的思路。
书中给出了类似归并排序的做法,在O(nlogn)时间内完成了计算。
思路就是在递增归并排序的基础上,做了改动:每次在merge两个子序列时,统计a和b组成的逆序对,a来自前一个递增子序列,b来自后一个递增子序列。
由于两个子序列都是递增的,这时候求a和b构成逆序对的数量就可以在O(n)内完成了。
当a前进一步时,就把第二个子序列中b所在位置及之前所有遍历过的元素的数量添加到count中。
count = 两个子序列内部的逆序对(用递归求出) + a和b所产生的逆序对个数
自己实现的代码如下:
#include <stdio.h> int FindInversePairCore(int *list, int* cache, int start, int end){ if(list == NULL) return 0; if(end - start <= 1){ return 0; } int mid = (start + end)/2; int count = 0; //逆序对计数器 count += FindInversePairCore(list, cache, start, mid); count += FindInversePairCore(list, cache, mid, end); for(int i = start;i < end;i++) cache[i] = list[i]; int j = start, k = mid, p = start; while(j < mid && k < end){ if(cache[j] <= cache[k]){ list[p++] = cache[j++]; count += (k - mid); }else{ list[p++] = cache[k++]; } } while(j < mid){ list[p++] = cache[j++]; count += (k - mid); } while(k < end){ list[p++] = cache[k++]; } return count; } int FindInversePair(int* list, int size){ int *cache = new int[size]; return FindInversePairCore(list, cache, 0, size); } // ====================测试代码==================== void Test(char* testName, int* data, int length, int expected) { if(testName != NULL) printf("%s begins: ", testName); if(FindInversePair(data, length) == expected) printf("Passed.\n"); else printf("Failed.\n"); } void Test1() { int data[] = {1, 2, 3, 4, 7, 6, 5}; int expected = 3; Test("Test1", data, sizeof(data) / sizeof(int), expected); } // 递减排序数组 void Test2() { int data[] = {6, 5, 4, 3, 2, 1}; int expected = 15; Test("Test2", data, sizeof(data) / sizeof(int), expected); } // 递增排序数组 void Test3() { int data[] = {4, 5, 6, 1, 2, 3}; int expected = 9; Test("Test3", data, sizeof(data) / sizeof(int), expected); } // 数组中只有一个数字 void Test4() { int data[] = {1}; int expected = 0; Test("Test4", data, sizeof(data) / sizeof(int), expected); } // 数组中只有两个数字,递增排序 void Test5() { int data[] = {1, 2}; int expected = 0; Test("Test5", data, sizeof(data) / sizeof(int), expected); } // 数组中只有两个数字,递减排序 void Test6() { int data[] = {2, 1}; int expected = 1; Test("Test6", data, sizeof(data) / sizeof(int), expected); } // 数组中有相等的数字 void Test7() { int data[] = {1, 2, 1, 2, 1}; int expected = 3; Test("Test7", data, sizeof(data) / sizeof(int), expected); } void Test8() { int expected = 0; Test("Test8", NULL, 0, expected); } int main() { Test1(); Test2(); Test3(); Test4(); Test5(); Test6(); Test7(); Test8(); return 0; }
书上代码:
// InversePairs.cpp : Defines the entry point for the console application. // // 《剑指Offer——名企面试官精讲典型编程题》代码 // 著作权所有者:何海涛 #include "stdafx.h" int InversePairsCore(int* data, int* copy, int start, int end); int InversePairs(int* data, int length) { if(data == NULL || length < 0) return 0; int* copy = new int[length]; for(int i = 0; i < length; ++ i) copy[i] = data[i]; int count = InversePairsCore(data, copy, 0, length - 1); delete[] copy; return count; } int InversePairsCore(int* data, int* copy, int start, int end) { if(start == end) { copy[start] = data[start]; return 0; } int length = (end - start) / 2; int left = InversePairsCore(copy, data, start, start + length); int right = InversePairsCore(copy, data, start + length + 1, end); // i初始化为前半段最后一个数字的下标 int i = start + length; // j初始化为后半段最后一个数字的下标 int j = end; int indexCopy = end; int count = 0; while(i >= start && j >= start + length + 1) { if(data[i] > data[j]) { copy[indexCopy--] = data[i--]; count += j - start - length; } else { copy[indexCopy--] = data[j--]; } } for(; i >= start; --i) copy[indexCopy--] = data[i]; for(; j >= start + length + 1; --j) copy[indexCopy--] = data[j]; return left + right + count; }
------------------------------------------------
Felix原创,转载请注明出处,感谢博客园!
posted on 2014-02-05 12:00 Felix Fang 阅读(208) 评论(0) 收藏 举报
浙公网安备 33010602011771号