求数组逆序对个数

题目描述
Description

有一个由N个实数构成的数组,如果一对元素A[i]和A[j]是倒序的,即i<j但是A[i]>A[j]则称它们是一个倒置,设计一个计算该数组中所有倒置数量的算法。要求算法复杂度为O(nlogn)

Input

输入有多行,第一行整数T表示为测试用例个数,后面是T个测试用例,每一个用例包括两行,第一行的一个整数是元素个数,第二行为用空格隔开的数组值。

Output

输出每一个用例的倒置个数,一行表示一个用例。

Sample Input 1

1
8
8 3 2 9 7 1 5 4

Sample Output 1

17

思路主要是在归并排序上做一个小的修改,降低蛮力法的时间复杂度,达到O(nlogn)。在合并过程中右边序列发现有一个值比左边序列小,那么左边序列从该值开始到mid的数,都和右边这个数构成逆序对(因为左右序列都是有序的)。

package LeetCode_19_12;

import java.util.Arrays;

public class 倒置个数191209 {

	int count = 0;

	public void mergesort(int[] arr) {
		sort(arr, 0, arr.length - 1);
	}

	public void sort(int[] arr, int L, int R) {
		if (L == R) {
			return;
		}
		int mid = L + ((R - L) >> 1);
		sort(arr, L, mid);
		sort(arr, mid + 1, R);
		merge(arr, L, mid, R);
	}

	public void merge(int[] arr, int L, int mid, int R) {

		int[] temp = new int[R - L + 1];
		int i = 0;
		int pa1 = L;
		int pa2 = mid + 1;
		while (pa1 <= mid && pa2 <= R) {

			if (arr[pa1] < arr[pa2]) {
				temp[i] = arr[pa1];
				i++;
				pa1++;
			} else {
				temp[i] = arr[pa2];
				i++;
				pa2++;
				count += mid - pa1 + 1;
				// 右边序列中只要有数比左边序列中数小,那么左边序列从这个数开始到结束的数都与右边序列构成逆序对。
				// 因为每次归并的序列都输有序的。
			}
		}
		// 两个序列比较然后将小的数插入temp,可能只比较了第一个数组的几个数另一个数组就到length
		// 所以要把剩下的数也插入temp
		while (pa1 <= mid) {// <=mid mid位置的数也要插入
			temp[i++] = arr[pa1++];
		}
		while (pa2 <= R) {
			temp[i++] = arr[pa2++];
		}
		// 一定要插入原数组
		for (i = 0; i < temp.length; i++) {
			arr[L + i] = temp[i];
		}
	}

	public static void main(String[] args) {

		int a[] = { 5, 4, 2, 1 };
		int b[] = { 8, 3, 2, 9, 7, 1, 5, 4 };
		倒置个数191209 p = new 倒置个数191209();
		p.mergesort(b);
		System.out.println(Arrays.toString(b));
		System.out.println(p.count);
	}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值