面试算法(三十六)数组中的逆序对
2014-07-17 14:50
169 查看
1、题目:在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
例如在数组{7,5,6,4}中,一共存在5个逆序对,分别是(7,6)、(7,5)、(7,4)、(6,4)、(5,4)。
直观反应是顺序扫描整个数组。每扫描到一个数字的时候,逐个比较该数字和它后面的数字的大小。若后面的数字比它小,则这两个数字就组成了一个逆序对。假设数组中含有n个数字,由于每个数字都要和O(n)个数字做比较,故时间复杂度是O(n^2)。
解法:
我们以数组{7,5,6,4}来分析。可以考虑先比较两个相邻的数字,先把数组分解成两个长度为2的子数组,再把这两个子数组拆分成两个长度为1的子数组。接下来一边合并相邻的子数组,一边统计逆序对的数目。
用两个指针的分别指向两个子数组的末尾,并每次比较两个指针指向的数字。若第一个子数组中的数字大于第二个子数组中的数字,则构成逆序对,并且逆序对的数目等于第二个子数组中剩余数字的个数。若小于则构不成。每一次比较时,都把较大的数字从后往前复制到一个辅助数组中去,确保辅助数组中的数字是递增排序的。在把较大的数字复制到辅助数组之后,把对应的指针向前移动一位,接下来进行下一轮比较。
总结过程:
先把数组分割成子数组,先统计出子数组内部的逆序对的数目,再统计出两个相邻子数组之间的逆序对的数目。其间还要对数组进行排序,实际上是归并排序。
例如在数组{7,5,6,4}中,一共存在5个逆序对,分别是(7,6)、(7,5)、(7,4)、(6,4)、(5,4)。
直观反应是顺序扫描整个数组。每扫描到一个数字的时候,逐个比较该数字和它后面的数字的大小。若后面的数字比它小,则这两个数字就组成了一个逆序对。假设数组中含有n个数字,由于每个数字都要和O(n)个数字做比较,故时间复杂度是O(n^2)。
解法:
我们以数组{7,5,6,4}来分析。可以考虑先比较两个相邻的数字,先把数组分解成两个长度为2的子数组,再把这两个子数组拆分成两个长度为1的子数组。接下来一边合并相邻的子数组,一边统计逆序对的数目。
用两个指针的分别指向两个子数组的末尾,并每次比较两个指针指向的数字。若第一个子数组中的数字大于第二个子数组中的数字,则构成逆序对,并且逆序对的数目等于第二个子数组中剩余数字的个数。若小于则构不成。每一次比较时,都把较大的数字从后往前复制到一个辅助数组中去,确保辅助数组中的数字是递增排序的。在把较大的数字复制到辅助数组之后,把对应的指针向前移动一位,接下来进行下一轮比较。
总结过程:
先把数组分割成子数组,先统计出子数组内部的逆序对的数目,再统计出两个相邻子数组之间的逆序对的数目。其间还要对数组进行排序,实际上是归并排序。
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; } 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; }
相关文章推荐
- C/C++面试之算法系列--1~n无序数组时间复杂度为O(n)排序
- C/C++面试之算法系列--去除数组中的重复数字
- 【有趣的面试算法题】 数组循环移动算法细究
- leetcode:Remove Duplicates from Sorted Array II (允许重复一次,去掉数组多余数字)【面试算法题】
- leetcode:Remove Duplicates from Sorted Array(去掉数组重复数字,常数空间限制)【面试算法题】
- C/C++面试之算法系列--整数数组的循环右移
- 面试经典(9)--求数组的逆序对
- 这是一个我面试某公司的算法题目:对一个字符数组进行排序,根据给定的字符,大于它的,放在数组的左边,小于它的,放在数组的右边,且数组中的元素之间的相对位置要保持不变。
- 笔试面试中关于数组的常见算法
- [面试算法]有一无符号整型数组,大小为10, 初始的数值随机,但在[0, 99]之间。请用C语言写一个过滤程序,令数组内的数据互不相等。
- 阿里巴巴面试算法题:有一个函数int getNum(),每运行一次可以从一个数组V[N]里面取出一个数,N未知,当数取完的时候,函数返回NULL。现在要求写一个函数int get(),这个函数运行一次可以从V[N]里随机取出一个数,而这个数必须是符合1/N
- 数组面试算法题
- 面试-算法 已经排好序的数组中求两个数的和等于N
- 面试100题系列之6给出洗牌的一个算法,并把洗好的牌放在一个整型的数组里
- 微软等数据结构+算法面试100题(39)-- 左旋数组中查找
- C/C++面试之算法系列--二维动态数组定义及二维静态数组与**P的区别
- [小算法] 使用递归将一个整数逆序放入一数组中
- 微软等数据结构+算法面试100题(9)--在一个int 数组里查找这样的数,它大于等于左侧所有数,小于等于右侧所有数。
- leetcode:Merge Sorted Array(合并两个有序数组到其中一个数组中)【面试算法题】
- 如何找出数组中第二大的数?(一道面试算法题的思考)