数组中的逆序对数(剑指offer36)

本文介绍了一种使用分治法高效计算数组中逆序对总数的方法,并提供了详细的C++实现代码。通过将数组不断分解成子序列,再将有序子序列合并的过程中统计逆序对数量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。

思路:判断两个数是否逆序就是判断前一个数是否大于后一个数,所以我们可以采用分治法,将一个数组序列折半分解为两个子序列,然后子序列继续对半分解,直至将子序列分解为两个数字。然后判断这两个数字是否逆序,如果逆序则逆序对数+1,然后将其合并为有序序列;将两个有序的子序列归并为一个新的有序序列,归并过程中统计逆序对数————因为两个序列都是有序序列,所以如果前一个序列的对头元素大于后一个序列的队头元素,则前一个序列中的所有元素相对于后一个序列的队头元素逆序,逆序对数就是前一个序列的长度,这样我们就可以统计出这两个序列中的逆序对数。一个序列的逆序对数是前半段序列的逆序对数+后半段序列逆序对数+归并这两个序列时新统计出来的逆序对数之和。

#include <stddef.h>

//统计逆序对数
int reverseOrderPair(int* array, int length) {
	if (NULL == array || 0 >= length) {
		return 0;
	}

	//辅助数组并利用array数组初始化
	int* copy = new int[length];
	for (int i = 0; i < length; ++i) {
		copy[i] = array[i];
	}

	int count = allReverseOrderPair(array, copy, 0, length - 1);

	delete[] copy;

	return count;
}

//统计整个序列的逆序对数
int allReverseOrderPair(int* array, int* copy, int start, int end) {
	if (NULL == array || NULL == copy || 0 > start || start > end) {
		return 0;
	}

	if (start < end) {
		int middle = (start + end) / 2;
		int left = allReverseOrderPair(array, copy, start, middle);
		int right = allReverseOrderPair(array, copy, middle + 1, end);
		int current = subReverseOrderPair(copy, array, start, middle, end);

		//逆序对数有三部分组成
		return left + right + current;
	}

	return 0;
}

//统计相邻的两个序列中的逆序对数
int subReverseOrderPair(int* array, int* copy, int start, int middle, int end) {
	if (NULL == array || NULL == copy || 0 > start || start > end) {
		return 0;
	}

	int i = start, j = middle + 1;
	int k = start, count = 0;

	//统计相邻两个序列中的逆序对数并归并这两个序列
	while (i <= middle && j <= end) {
		if (array[i] < array[j]) {
			copy[k++] = array[i++];
		} else {
			copy[k++] = array[j++];

			//计算array[i]相当于另一个序列的逆序对数
			count = count + middle - i + 1;
		}
	}

	while (i <= middle) {
		copy[k++] = array[i++];
	}

	while (j <= end) {
		copy[k++] = array[j++];
	}

	return count;

测试代码

/*
 *
 *  Created on: 2014-4-24 09:37:29
 *      Author: danDingCongRong
 */

#include<iostream>
using namespace std;

//输入各个数组元素
void inputArray(int* array, int length) {
	cout << "输入这个数组中的各个数字:" << endl;
	for (int i = 0; i < length; ++i) {
		cin >> array[i];
	}
}

int main() {
	int length = 0;
	cout << "请输入数组的长度:" << endl;
	while (cin >> length) {
		int* x = new int[length];
		inputArray(x, length);

		cout << "逆序对数:" << reverseOrderPair(x, length) << endl;

		delete[] x;

		cout << "请输入数组的长度:" << endl;
	}

	return 0;
}


注:参考自剑指offer



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值