java实现求逆序对
1 问题描述
给定一个随机数数组,求取这个数组中的逆序对总个数。要求时间效率尽可能高。
那么,何为逆序对?
引用自百度百科:
设 A 为一个有 n 个数字的有序集 (n>1),其中所有数字各不相同。
如果存在正整数 i, j 使得 1 ≤ i < j ≤ n 而且 A[i] > A[j],则 <A[i], A[j]> 这个有序对称为 A 的一个逆序对,也称作逆序数。
例如,数组(3,1,4,5,2)的逆序对有(3,1),(3,2),(4,2),(5,2),共4个。
2 解决方案
2.1 蛮力法
初步一看,使用蛮力是最直接也最简单的方法,但是时间效率为O(n^2)。
即从第1个元素,开始依次和后面每一个元素进行大小比较,若大于,则逆序对个数加1。
package com.liuzhen.systemExe;
public class Main{
//蛮力法求取数组A中逆序对数
public int bruteReverseCount(int[] A) {
int result = 0;
for(int i = 0;i < A.length;i++) {
for(int j = i;j < A.length;j++) {
if(A[i] > A[j])
result++;
}
}
return result;
}
//获取一个随机数数组
public int[] getRandomArray(int n) {
int[] result = new int[n];
for(int i = 0;i < n;i++) {
result[i] = (int)( Math.random() * 50); //生成0~50之间的随机数
}
return result;
}
public static void main(String[] args){
long t1 = System.currentTimeMillis();
Main test = new Main();
int[] A = test.getRandomArray(50000);
int result = test.bruteReverseCount(A);
long t2 = System.currentTimeMillis();
System.out.println("使用蛮力法得到结果:"+result+", 耗时:"+(t2 - t1)+"毫秒");
}
}
运行三次的结果:
使用蛮力法得到结果:612226389, 耗时:8094毫秒
使用蛮力法得到结果:610311942, 耗时:8015毫秒
使用蛮力法得到结果:610657465, 耗时:8079毫秒
2.2 分治法(归并排序)
除了蛮力法,此处可以借用归并排序的思想来解决此题,此时时间复杂度为O(n*logn)。归并排序,具体是先进行对半划分,直到最后左半边数组只有一个元素,右半边数组中也只有一个元素时,此时开始进行回溯合并。那么,计算逆序对个数的关键,就在于此处的回溯合并过程,当左半边元素(PS:回溯过程中,左半边和右半边元素均已是升序排序)中出现大于右半边元素时,那么左半边这个元素及其后面的所有元素均大于这个右半边元素,记这些元素个数为len,那么逆序对个数要自增len。
package com.liuzhen.systemExe;
public class Main{
public long count = 0; //全局变量,使用合并排序,计算逆序对数
//使用归并排序方法计算数组A中的逆序对数
public void getReverseCount(int[] A) {
if(A.length > 1) {
int[] leftA = getHalfArray(A, 0); //数组A的左半边元素
int[] rightA = getHalfArray(A, 1); //数组A的右半边元素
getReverseCount(leftA);
getReverseCount(rightA);
mergeArray(A, leftA, rightA);
}
}
//根据judge值判断,获取数组A的左半边元素或者右半边元素
public int[] getHalfArray(int[] A, int judge) {
int[] result;
if(judge == 0) { //返回数组A的左半边
result = new int[A.length / 2];
for(int i = 0;i < A.length / 2;i++)
result[i] = A[i];
} else { //返回数组的右半边
result= new int[A.length - A.length / 2];
for(int i = 0;i < A.length - A.length / 2;i++)
result[i] = A[A.length / 2 + i];
}
return result;
}
//合并数组A的左半边和右半边元素,并按照非降序序列排列
public void mergeArray(int[] A, int[] leftA, int[] rightA) {
int len = 0;
int i = 0;
int j = 0;
int lenL = leftA.length;
int lenR = rightA.length;
while(i < lenL && j < lenR) {
if(leftA[i] > rightA[j]) {
A[len++] = rightA[j++]; //将rightA[j]放在leftA[i]元素之前,那么leftA[i]之后lenL - i个元素均大于rightA[j]
count += (lenL - i); //合并之前,leftA中元素是非降序排列,rightA中元素也是非降序排列。所以,此时就新增lenL - i个逆序对
} else {
A[len++] = leftA[i++];
}
}
while(i < lenL)
A[len++] = leftA[i++];
while(j < lenR)
A[len++] = rightA[j++];
}
//获取一个随机数数组
public int[] getRandomArray(int n) {
int[] result = new int[n];
for(int i = 0;i < n;i++) {
result[i] = (int)( Math.random() * 50); //生成0~50之间的随机数
}
return result;
}
public static void main(String[] args){
long t1 = System.currentTimeMillis();
Main test = new Main();
int[] A = test.getRandomArray(50000);
test.getReverseCount(A);
long t2 = System.currentTimeMillis();
System.out.println("分治法得到结果:"+test.count+", 耗时:"+(t2 - t1)+"毫秒");
}
}
运行三次结果:
分治法得到结果:612226489, 耗时:36毫秒
分治法得到结果:610481152, 耗时:35毫秒
分治法得到结果:612161208, 耗时:32毫秒
java实现求逆序对的更多相关文章
- 算法笔记_065:分治法求逆序对(Java)
目录 1 问题描述 2 解决方案 2.1 蛮力法 2.2 分治法(归并排序) 1 问题描述 给定一个随机数数组,求取这个数组中的逆序对总个数.要求时间效率尽可能高. 那么,何为逆序对? 引用自百度 ...
- 归并排序&&归并排序求逆序对
归并排序 归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用.将已有序的子序列合并,得到完全有序的序 ...
- HDU 3743 Frosh Week(归并排序求逆序对)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3743 题目意思就是给你一个长为n的序列,让你求逆序对.我用的是归并排序来求的.归并排序有一个合并的过程 ...
- AC日记——codevs 1688 求逆序对
1688 求逆序对 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题解 查看运行结果 题目描述 Description 给定一个序列a1,a2,…, ...
- POJ2299Ultra-QuickSort(归并排序 + 树状数组求逆序对)
树状数组求逆序对 转载http://www.cnblogs.com/shenshuyang/archive/2012/07/14/2591859.html 转载: 树状数组,具体的说是 离散化+树 ...
- codevs1688 求逆序对
题目描述 Description 给定一个序列a1,a2,…,an,如果存在i<j并且ai>aj,那么我们称之为逆序对,求逆序对的数目 数据范围:N<=105.Ai<=105. ...
- HDU 4911 http://acm.hdu.edu.cn/showproblem.php?pid=4911(线段树求逆序对)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4911 解题报告: 给出一个长度为n的序列,然后给出一个k,要你求最多做k次相邻的数字交换后,逆序数最少 ...
- SGU 180 Inversions(离散化 + 线段树求逆序对)
题目链接:http://acm.sgu.ru/problem.php?contest=0&problem=180 解题报告:一个裸的求逆序对的题,离散化+线段树,也可以用离散化+树状数组.因为 ...
- 树状数组求逆序对:POJ 2299、3067
前几天开始看树状数组了,然后开始找题来刷. 首先是 POJ 2299 Ultra-QuickSort: http://poj.org/problem?id=2299 这题是指给你一个无序序列,只能交换 ...
随机推荐
- [hdu5323]复杂度计算,dfs
题意:求最小的线段树的右端点(根节点表示区间[0,n]),使得给定的区间[L,R]是线段树的某个节点. 数据范围:L,R<=1e9,L/(R-L+1)<=2015 思路:首先从答案出发来判 ...
- [BC冠军赛(online)]小结
A Movie 题意:给你n个区间,判断能否选出3个不相交的区间. 思路:令f(i)表示能否选出两个不相交区间并且以区间i为右区间的值,g(i)表示能否选出两个不相交区间并且以区间i为左区间的值,如果 ...
- [hdu2594]kmp水题
题意:求最长的a的前缀同时满足是b的后缀,把a,b连在一起,kmp跑一下,迭代next直到长度小于等于a,b长度的最小值为止,即为答案. #pragma comment(linker, "/ ...
- 华为的快服务智慧平台是牛皮还是牛B?
华为快服务智慧平台是牛皮还是牛B? 来到快服务论坛专区的老铁们想必对快服务有一定的了解,那么作为华为快服务统一接入分发核心的华为快服务智慧平台是怎样的存在呢?想必带着眼睛阅读的小伙伴都已经看出来了 ...
- python100例 1-10
001 数字重组 题目:有四个数字:1.2.3.4,能组成多少个互不相同且无重复数字的三位数?各是多少? for i in range(1,5): for j in range(1,5): for k ...
- Spring MVC 函数式编程进阶
1. 前言 上一篇对 Spring MVC 的函数式接口编程进行了简单入门,让很多不知道的同学见识了这种新操作.也有反应这种看起来没有传统写法顺眼,其实大家都一样.但是我们还是要敢于尝试新事物.Jav ...
- spark机器学习从0到1特征变换-标签和索引的转化(十六)
一.原理 在机器学习处理过程中,为了方便相关算法的实现,经常需要把标签数据(一般是字符串)转化成整数索引,或是在计算结束后将整数索引还原为相应的标签. Spark ML 包中提供了几个相关的转换器 ...
- 微信小程序通信录
第一步:phone.wxml中 <view bindlongtap="clickPhone">{{phoneNum}}</view> 第二步:phone.j ...
- python -使用Requests库完成Post表单操作
""" 使用Requests库完成Post表单操作 """ #_*_codingn:utf8 _*_ import requests fro ...
- 模拟SWPU邮件登录页面
模拟SWPU邮件登录页面设计流程 一.开发工具准备 本次开发该页面时使用的开发工具为vscode—— 在下载安装完成后,需要下载各类插件——如汉化.通过浏览器打开网页插件等. 二.开发过程 首先,打开 ...