// 面试题51:数组中的逆序对 // 题目:在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组 // 成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。 #include <cstdio> int InversePairsCore(int* data, int* copy, int start, int end); int InversePairs(int* data, int length) { if (data == nullptr || length < 0) return 0; int* copy = new int[length]; //复制原数组, 辅助数组 for (int i = 0; i < length; ++i) copy[i] = data[i]; int number = InversePairsCore(data, copy, 0, length - 1); delete[] copy; return number; } int InversePairsCore(int* data, int* copy, int start, int end) //这里注意输入, 始终用data更新copy排序 { if (start == end) //数组只有一个元素 { copy[start] = data[start]; return 0; } int length = (end - start) / 2; //分割当前数组 //copy和data分别作为辅助数组 //递归调用时data作为辅助数组,递归调用完成后data前后半段已经排好序,下来程序中copy作为辅助数组对前后半段进行排序 int left = InversePairsCore(copy, data, start, start + length); //前半段数组逆序对数 int right = InversePairsCore(copy, data, start + length + 1, end); //计算当前两个数组逆序对数 int i = start + length; //前半段数组最后一位数字 int j = end; //后半段数组最后一位数字 int index = end; //排序数组的索引 int count = 0; while (i >= start && j >= start + length + 1) //从后往前索引,直到前半段或者后半段数组索引完成 { if (data[i] > data[j]) //如果左边数字大,则存在逆序数 { copy[index--] = data[i--]; //逆序对个数等于 j下标距离所处的段开头的距离 count += j - (start + length + 1) + 1; } else //后面大于前面,只用赋值,不属于逆序对情况 copy[index--] = data[j--]; } //如果前半段数组未索引完 for (; i >= start; --i) copy[index--] = data[i]; //如果后半段数组未索引完 for (; j >= start + length + 1; --j) copy[index--] = data[j]; return left + right + count; }
// ====================测试代码==================== void Test(char* testName, int* data, int length, int expected) { if(testName != nullptr) printf("%s begins: ", testName); if(InversePairs(data, length) == expected) printf("Passed. "); else printf("Failed. "); } 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", nullptr, 0, expected); } int main(int argc, char* argv[]) { Test1(); Test2(); Test3(); Test4(); Test5(); Test6(); Test7(); Test8(); return 0; }
分析:归并排序,详情见博客
class Solution { public: int InversePairs(vector<int> data) { int length = data.size(); if (data.empty()) return 0; vector<int> copy; for (int i = 0; i < length; ++i) copy.push_back(data[i]); long count = InversePairs(data, copy, 0, length - 1); return count%1000000007; } long InversePairs(vector<int> &data, vector<int> ©, int start, int end) { if (start == end) { copy[start] = data[start]; return 0; } int length = (end - start) / 2; long left = InversePairs(copy, data, start, start + length); long right = InversePairs(copy, data, start + length + 1, end); int i = start + length; int j = end; int index = end; long count = 0; while (i >= start && j >= start + length + 1) { if (data[i] > data[j]) { copy[index--] = data[i--]; count += j - (start + length + 1) + 1; } else copy[index--] = data[j--]; } for (; i >= start; --i) copy[index--] = data[i]; for (; j >= start + length + 1; --j) copy[index--] = data[j]; return count + left + right; } };