标签:array
题目描述:http://ac.jobdu.com/problem.php?pid=1348
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
如输入{7,5,6,4}中,共存在5个逆序对:(7,6) (7,5) (7,4) (6,4) (5,4)
解析:
从第一个数字开始,让它和后面的每个数字比较,找出所有逆序对。时间复杂度
只要让一个数字和其他的每个数字比较,那么时间就是
采用merge-sort的思路:
将原数组,平均分成左右部分,找出左右子数组中的逆序对(并将左右数组排序),再找出左右子数组合并时的逆序对,将有序的左右数组归并到1个数组。
如:左数组{5,7}, 右数组{4,6},将左右数组合并
因为7大于6,则逆序对数+2(右数组的剩余长度);5 < 6 不产生逆序对;5 > 4,逆序对数+1。
即:
(1)如果现存左数组的最大值大于现存右数组的最大值,则逆序对数 + 右数组的长度;
如果现存左数组的最大值小于现存右数组的最大值,则不存在逆序对;
(2)将左右的最大值,放到缓存数组;使用归并算法将左右最终合并成一个有序的数组。
最终逆序对的总数 = 左的逆序对数 + 右的逆序对数 + 左右合并的逆序对数;
#include <iostream>
using namespace std;
int InvertPairCore(int* nums, int* copy, int start, int end);
int InvertPair(int nums[], int length) {
if (nums == NULL || length <= 0)
return 0;
int *copy = new int[length];
for (int i = 0; i < length; i++)
copy[i] = nums[i];
int result = InvertPairCore(nums, copy, 0, length-1);
delete copy;
return result;
}
int InvertPairCore(int* nums, int* copy, int start, int end) {
if (nums == NULL || copy == NULL || start >= end)
return 0;
int mid = (start+end) / 2;
int left_pairs = 0, right_pairs = 0;
left_pairs = InvertPairCore(copy, nums, start, mid); // 注意此处,输入数组是copy,因为copy已经有序
right_pairs = InvertPairCore(copy, nums, mid+1, end);
int count = 0; // 左右字符串相连时的逆序对的个数
int i = mid, j = end;
int k = end; // copy index
// 将左右有序子数组归并成一个有序数组
while (i >= start && j >= mid+1) {
if (nums[i] > nums[j]) {
copy[k--] = nums[i--];
count += j-mid;
} else {
copy[k--] = nums[j--];
}
}
while (i >= start)
copy[k--] = nums[i--];
while (j >= mid+1)
copy[k--] = nums[j--];
return left_pairs + right_pairs + count;
}
int main() {
int nums[] = {7,5,6,4};
cout << InvertPair(nums, sizeof(nums)/sizeof(nums[0])) << endl;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:array
原文地址:http://blog.csdn.net/quzhongxin/article/details/47124299