版权声明:本文为博主NJU_ChopinXBP原创文章,发表于CSDN,仅供交流学习使用,转载请私信或评论联系,未经博主允许不得转载。感谢您的评论与点赞。 https://blog.csdn.net/qq_20304723/article/details/83055616
2018.10.15
这道题也是一道时间空间效率题,表面上很容易能够想出复杂度为o()的算法。可以用归并排序的思想将其优化成o(nlogn)。
1.创建一个归并排序的排序数组copy。
2.将数组拆分为左右两个部分,逆序总个数=左半部分逆序对个数+右半部分逆序对个数+跨左右的逆序对个数
3.递归求解左半部分和右半部分
4.对于跨左右的逆序对个数计算,将左半部分尾指针lefttail对应值依次与右半部分尾指针righttail对应值进行比较,若lefttail对应值大于righttail对应值,则逆序对个数为右半部分头指针至尾指针的元素个数,即存在(righttail - righthead + 1)个逆序对。(前提是左右部分已经分别递增排序)。
5.计算过程中依次将尾指针对应值比较较大者自右向左依次放入整段copy和原序列中,使其排成一段递增排序序列。
最终可以递归求解出总的逆序对个数,同时也将原序列归并排序为递增序列。计算过程中需要注意题目附加条件,防止数值过大进行取余操作。
题目描述
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
输入描述:
题目保证输入的数组中没有的相同的数字
数据范围:
对于%50的数据,size<=10^4
对于%75的数据,size<=10^5
对于%100的数据,size<=2*10^5
Java实现:
/**
*
* @author ChopinXBP
* 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。
* 输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
*
*/
public class InversePairs_34 {
public static void main(String[] args) {
// TODO Auto-generated method stub
// int[] array = {7, 5, 6, 4};
int[] array = {1,2,3,4,5,6,7,0};
System.out.println(InversePairs(array));
}
//模拟归并排序操作,复杂度o(nlogn)
public static int InversePairs(int [] array) {
if(array == null) return -1;
int head = 0;
int tail = array.length - 1;
int[] copy = new int[array.length]; //记录归并排序后的数组
int count = Solution(array, copy, head, tail);
return count;
}
public static int Solution(int[] array, int[] copy, int head, int tail){
if(head == tail){
copy[head] = array[head];
return 0;
}
int lefttail = (head + tail) / 2; //左半部分尾指针
int righthead = lefttail + 1; //右半部分头指针
int righttail = tail; //右半部分尾指针
int leftcount = Solution(array, copy, head, lefttail) % 1000000007;
int rightcount = Solution(array, copy, righthead, tail) % 1000000007;
//将左半部分尾指针对应值依次与右半部分尾指针对应值进行比较,若lefttail对应值大于righttail对应值,则存在(righttail - righthead + 1)个逆序对
//计算过程中依次将尾指针对应值比较较大者自右向左依次放入整段copy和原序列中,使其排成一段递增排序序列。
int midcount = 0;
int indexCopy = tail;
while(lefttail >= head && righttail >= righthead){
if(array[lefttail] > array[righttail]){
midcount += righttail - righthead + 1;
copy[indexCopy--] = array[lefttail--];
if(midcount >= 1000000007) midcount %= 1000000007; //防止数值过大先求余
}else{
copy[indexCopy--] = array[righttail--];
}
}
while(lefttail >= head){
copy[indexCopy--] = array[lefttail--];
}
while(righttail >= righthead){
copy[indexCopy--] = array[righttail--];
}
for(int i = head; i <= tail; i++){
array[i] = copy[i];
}
return (leftcount + rightcount + midcount) % 1000000007;
}
}
C++实现示例:
class Solution {
public:
int InversePairs(vector<int> data)
{
if(data.empty() || data.size()==0)
return 0;
int length=data.size();
vector<int> copy;
for(auto iter=data.begin();iter!=data.end();iter++)
copy.push_back(*iter);
//for(int i=0;i<length-1;i++)
// copy[i]=data[i];
long long count=0;
count=InversePairsCore(data,copy,0,length-1);
return count%1000000007;
}
long long InversePairsCore(vector<int>& data,vector<int>& copy,int start,int end)
{
if(start==end)
{
copy[start]=data[start];
return 0;
}
int length=(end-start)>>2;
long long left;
left=InversePairsCore(copy,data,start,start+length);
long long right;
right=InversePairsCore(copy,data,start+length+1,end);
int i=start+length;
int j=end;
int indexCopy=end;
long long 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;
}
};
测试代码:
// ====================测试代码====================
void Test(char* testName, int* data, int length, int expected)
{
if(testName != NULL)
printf("%s begins: ", testName);
if(InversePairs(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[] = {1, 2, 3, 4, 5, 6};
int expected = 0;
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 _tmain(int argc, _TCHAR* argv[])
{
Test1();
Test2();
Test3();
Test4();
Test5();
Test6();
Test7();
Test8();
return 0;
}
#Coding一小时,Copying一秒钟。留个言点个赞呗,谢谢你#