算法提高 逆序对 java 题解 620

问题描述

  SORT公司是一个专门提供排序服务的公司,该公司的宗旨是:“顺序是美丽的”。他们的工作是通过一系列移动,将某些物品按顺序摆好。他们的服务是通过工作量来计算的,即移动物品的次数。所以,在工作前必须先考察工作量,以便向客户提出收费数目。
  用户并不需要知道精确的移动次数,实质上,大多数人都是凭感觉来认定这一列物品的混乱程度。根据SORT公司的经验,人们一般是根据“逆序对”的数目多少来称呼这一序列的混乱程度。假设将序列中第I件物品的参数定义为Ai,那么排序就是将A1,……An从小到大排序。若i<j且Ai>Aj,则<i,j>就为一个“逆序对".
  SORT公司请你写一个程序,在尽量短的时间内统计出”逆序对“的数目。

输入格式

  第1行为n(1<=n<=100000)
  接下来N行,每行一个长整数型范围内的整数。

输出格式

  一个整数,为逆序对的数目。

样例输入

5
3
1
4
5
2

样例输出

4


解题思路:

求逆序对的个数,如果仅仅用两层for循环暴力求解肯定会超时,可以利用归并排序的思想,在排序的过程中将逆序对的个数统计出来。

比如,当归并到【(2,4,7)(1,5,6)】时,对于右边的1,左边的三个数都是符合条件的逆序对,所以只需满足:当归并时,右边的数字小于左边的数字,则左边的这一数字之后的数字都满足条件,做累加。

另外,当数组为降序时,逆序对为n*(n - 1)/ 2。n最大可以取到10w,所以最后输出的数字应为long型。

归并排序算法见:

归并排序icon-default.png?t=M0H8https://blog.csdn.net/weixin_48898946/article/details/122568427

java代码:

import java.io.*;

public class Main {
	public static void main(String[] args) throws NumberFormatException, IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int n = Integer.parseInt(br.readLine());
		int []arr = new int[n];
		for(int i = 0; i < n; i++) {
			arr[i] = Integer.parseInt(br.readLine());
		}
		Merge test = new Merge(arr);
		test.divide(0, arr.length - 1);
		System.out.println(test.ans);
	}
}
class Merge{
	int []arr;
	int []temp;
	int ans = 0;
	
	public Merge(int[] arr) {
		this.arr = arr;
		temp = new int[arr.length];
	}
	
	public void divide(int start, int end) {
		if(start < end) {
			int mid = (start + end) / 2;
			divide(start, mid);
			divide(mid + 1, end);
			merge(start, mid, end);
		}
	}
	
	public void merge(int start, int mid, int end) {
		int i = start;
		int j = mid + 1;
		int index = 0;
		while(i <= mid && j <= end) {
			if(arr[i] <= arr[j]) {
				temp[index++] = arr[i];
				i++;
			}else {
				temp[index++] = arr[j];
				j++;
				ans += mid - i + 1;
			}
		}
		while(i <= mid) {
			temp[index++] = arr[i];
			i++;
		}
		while(j <= end) {
			temp[index++] = arr[j];
			j++;
		}
		index = 0;
		for(i = start; i <= end; i++) {
			arr[i] = temp[index++];
		}
	}
}

提交截图:

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值