【一些题】剑指offer:数组中的逆序对

来源:互联网 发布:淘宝联盟链接有效期 编辑:程序博客网 时间:2024/06/05 16:16

方法一:顺序扫描数组,,每扫描一个数字,就逐个比较该数字和它后面数字,判断是否为逆序对。时间复杂度为O(n^2)。程序如下:

int NumReversePair(int * num, int length);void main(){clock_t ClockBegin = clock();int num[4] = {7,5,6,4};int result = NumReversePair(num, 4);clock_t ClockEnd = clock();cout << result << endl;cout << ClockEnd-ClockBegin << "ms" <<endl;system("pause");return;}int NumReversePair(int * num, int length){if(!num||length < 1)return -1;int count = 0;for(int begin = 0; begin < length-1; ++begin){for(int i = begin+1; i < length; ++i){if(num[begin] > num[i])++count;}}return count;}

**********************************************************

方法二:采用分割+归并的方法(见剑指offer面试题36)。程序如下

int NumReversePair(int num[], int begin, int end);void main(){clock_t ClockBegin = clock();const int L = 5;int num[L] = {7,5,6,4,4};int result = NumReversePair(num, 0, 4);//int result = NumReversePair(num, 5);clock_t ClockEnd = clock();cout << result << endl;cout << ClockEnd-ClockBegin << "ms" <<endl;system("pause");return;}int NumReversePair(int num[], int begin, int end){int length = end - begin + 1; if(!num || length <=0)return -1;if(length == 1)return 0;int mid = begin + (length >> 1);//int sorted[length] = {0};//局部数组,用于储存合并后的两个小数组vector<int> sorted(length, 0);int p1 = mid - 1, p2 = end;//p1是前半个数组指向最后元素的指针,p2是后半个数组指向最后元素的指针int current_result = length -1;//局部数组sorted中的当前位置int num_second_subsequence = end-mid+1;//后半个子数组中剩余元素个数int count = 0;//统计前,后两个子数组内部的逆序对count += (NumReversePair(num, begin, mid - 1) + NumReversePair(num, mid, end)); //统计前,后两个子数组之间的逆序对,并将排好序的结果放在一个局部数组中while(p1 >= begin && p2 >= mid){if(num[p1] > num[p2]) //前子数组中数字大于后子数组中数字{sorted[current_result] = num[p1]; // 移入最大值到局部数组--p1;--current_result;count += num_second_subsequence; //增加逆序数}else{sorted[current_result] = num[p2];--p2;--current_result;--num_second_subsequence;}}//将剩余元素复制到局部数组中if(p1 >= begin){for(int i = p1; p1 >=begin; --p1){sorted[current_result] = num[p1];--current_result;--p1;}}else{for(int i = p2; p2 >= mid; --p2){sorted[current_result] = num[p2];--current_result;--p2;}}//将结果局部数组中排好序的结果复制回原数组for(int i = begin, j = 0; i <= end; ++i,++j){num[i] = sorted[j];}return count;}

*******************************************

方法二思考:在方法二中,可以看到各个循环中都有边界值,在写方法二的程序时,反复出了多次错误,不断修改才得到了现在的程序。总结为什么会有这么多错误,是因为:经常在现在是begin的地方,写成了0;现在是end的地方,开始写成了length-1.在很多情况下也是正常运行的。但是测试到一定情况时,总会出错的。

如何避免这种边界出错问题呢,小结如下:

——》凡是出现“硬编码”的地方,都是最容易出现边界错误的地方(“硬编码”)

——》为什么在写程序时会写出硬编码呢,往往是因为以特定的例子(如最开始的例子num【0,length-1】)作为思考对象。

——》减少错误的方法:因此,在写程序时可以尽量考虑general的例子(如num【begin,end】);或者是以特定的例子(如num【0,length-1】)编码,最后认真考虑所有带有“硬编码”的地方

0 0