题目:
在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。例如在数组{7,5,6,4}中一共存在5对逆序对,分别是(7,6),(7,5),(7,4),(6,4),(5,4)
基本思想:
解法一:O(n^2)
最简单的想法就是遍历每一个元素,让其与后面的元素对比,如果大于则count++,但是这样的时间复杂度是O(n^2)。
解法二:O(nlogn)
归并排序思路:
例如7,5,4,6可以划分为两段7,5和4,6两个子数组
1.在7,5中求出逆序对,因为7大于5所以有1对
2.在6,4中求出逆序对,因为6大于4所以逆序对再加1,为2
3.对7,5和6,4进行排序,结果为5,7,和4,6
4.设置两个指针分别指向两个子数组中的最大值,p1指向7,p2指向6
5.比较p1和p2指向的值,如果大于p2,因为p2指向的是最大值,所以第二个子数组中有几个元素就有几对逆序对(当前有两个元素,逆序对加2,2+2=4),7>6,比较完之后将p1指向的值放入辅助数组里,辅助数组里现在有一个数字7,然后将p1向前移动一位指向5
6.再次判断p1和p2指向的值,p1小于p2,因为p1指向的是第一个子数组中最大值,所以子数组中没有能和当前p2指向的6构成逆序对的数,将p2指向的值放入辅助数组,并向前移动一位指向4,此时辅助数组内为6,7
7.继续判断p1(指向5)和p2(指向4),5>4,第二个子数组中只有一个数字,逆序对加1,4+1=5,为5对,然后将5放入辅助数组,第一个子数组遍历完毕,只剩下第二个子数组,当前只有一个4,将4也放入辅助数组,函数结束。辅助数组此时为4,5,6,7.逆序对为5.
#include <iostream> using namespace std; 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); int i=start+length; //i初始化为前半段最后一个数字的下标 int j=end; //j初始化为后半段最后一个数字的下标 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; } 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; } void main() { int a[4]={7,5,6,4}; int result=InversePairs(a,4); cout<<result<<endl; }
时间复杂度为O(nlogn),但是要一个长度为n的辅助数组,所以空间复杂度为O(n)。
时间: 2024-10-02 22:08:48