逆序对java_逆序对
求逆序对问题用归并排序的时间复杂度比暴力算法更低。
假设有一个数组{8,1,2,5,7,4,3,6}
首先归并排序第一次对数组进行分割 8 1 2 5 7 4 3 6
二次分割 8 1 25 74 36
三次分割 8 1 2 5 7 4 3 6
第一次合并 18 25 74 36 reorder[1]=2, order[1]=2
//用reorder[i]来记录第i次合并中存在的逆序对数,order[i]来记录第i次合并中存在的顺序对数。
第二次合并 1258 3467 reorder[2]=5, order[2]=3
第三次合并 12345678 reorder[3]=6, order[3]=10
那么数组{8,1,2,5,7,4,3,6}中存在的逆序对就等于reorder[1]+reorder[2]+reorder[3]=13
将数组{8,1,2,5,7,4,3,6}每2^2个为一组进行翻转{5,2,1,8,6,3,4,7}
首先归并排序第一次对数组进行分割 5 2 1 8 6 3 4 7
二次分割 5 2 18 63 47
三次分割 5 2 1 8 6 3 4 7
第一次合并 25 18 36 47 reorder[1]=2, order[1]=2
第二次合并 1258 3467 reorder[2]=3, order[2]=5
第三次合并 12345678 reorder[3]=6, order[3]=10
那么数组{5,2,1,8,6,3,4,7}中存在的逆序对就等于reorder[1]+reorder[2]+reorder[3]=11
由此我们可以观察到对数组每2^2个进行翻转时,reorder[1]和order[1]进行了互换,reorder[2]和order[2]亦是如此。
所以对数组每2^i个进行翻转时,我们可以把1~i的reorder和order数组元素互换即可继续通过计算reorder数组的累加和来求得数组的逆序对数。
import java.util.ArrayList;
import java.util.Scanner;
public class Main {
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int N = 1 << n;
int[] a = new int[N];
int[] b = new int[N];//用来存储数组的逆序,对逆序的数组进行一次归并排序可以直接得到order数组
int[] order = new int[n + 1];//为了便于计算,所以设置order下标是1~n,因此数组大小为n+1
int[] reorder = new int[n + 1];
for (int i = 0; i < N; i++)
{
a[i] = sc.nextInt();
b[N - i - 1] = a[i];
}
MergeSort(a, 0, N - 1, reorder, n);//对整个数组进行归并排序,n表示对reorder[1]~reorder[n]进行初始化
MergeSort(b, 0, N - 1, order, n);//对整个逆序数组进行归并排序,完成对order[1]~order[n]的初始化
int m = sc.nextInt();
while(m-- > 0)
{
int count = 0;
int q = sc.nextInt();
for (int i = 1; i <= q; i++) //像之前讲的,将1~q的reorder[i]和order[i]进行互换
{
int temp = reorder[i];
reorder[i] = order[i];
order[i] = temp;
}
for (int i = 1; i <= n; i++)
{
count+= reorder[i];//累加reorder数组,求得对数组中每2^q个元素进行翻转后的逆序对数
}
System.out.println(count);
}
}
public static void MergeSort(int[] a , int left, int right, int[] reorder, int index)
{
if(left < right)
{
int mid = (right + left) / 2;
MergeSort(a, left, mid, reorder,index - 1);
MergeSort(a, mid + 1, right, reorder,index -1);
if(a[mid] > a[mid+1])//如果a[mid]<=a[mid+1],则原数组有序,不需要合并
Merge(a, left, right,reorder, index);
}
}
public static void Merge(int[] a, int left, int right,int[] reorder, int index)//index表示对reorder[index]进行初始化
{
int mid = (right + left) / 2;
int Length1 = mid - left + 1;
int Length2 = right - mid;
int[] l = new int[Length1];//存储a[left]~a[mid]
int[] r = new int[Length2];//存储a[mid+1]~a[right]
System.arraycopy(a, left, l, 0, Length1);//对l进行初始化
System.arraycopy(a, mid + 1, r, 0, Length2);//对r进行初始化
int i = 0;
int j = 0;
int c= 0;
int k = left;
while(i < Length1 && j < Length2)
{
if(l[i] <= r[j])
{
a[k] = l[i];
i++;
}
else
{
a[k] = r[j];
j++;
c += Length1 - i;//当l[i]>r[j]时,因为l是递增序列,所以l[i]~l[Length1-1]均>r[j],所以有Length1-i个元素大于r[j]
}
k++;
}
System.arraycopy(l, i, a, k, Length1 - i);//前面归并排序MergeSort中调用Merge合并的条件是a[mid]>a[mid+1],因为当a[mid]<=a[mid+1]时说明原数组有序,无需合并。l[Length1-1]>r[Length2-1],即l数组的最大值大于r数组的最大值,所以当r中的数全部进入a数组后,l数组中仍有剩余。
reorder[index] += c;
}
}
逆序对java_逆序对相关推荐
- OpenCV求逆(伪逆)矩阵函数
转自 double invert(InputArray src, OutputArraydst, int flags=DECOMP_LU); 功能:用以求取一个矩阵的逆或者伪逆. src: 输入,浮点 ...
- 3.4 矩阵 $A,A^T,A^TA,AA^T$ 秩相等,左逆和右逆
矩阵 A,AT,ATA,AATA,A^T,A^TA,AA^TA,AT,ATA,AAT 秩相等,左逆和右逆 令 r=rankAr=rank Ar=rankA ,因为零空间秩为 n−rn-rn−r ,零空 ...
- 矩阵的逆、伪逆、左右逆,最小二乘,投影矩阵
主要内容: 矩阵的逆.伪逆.左右逆 矩阵的左逆与最小二乘 左右逆与投影矩阵 一.矩阵的逆.伪逆.左右逆 1.矩阵的逆 定义: 设A是数域上的一个n阶方阵,若在相同数域上存在另一个n阶矩阵B,使得: A ...
- 51Nod-1019 逆序数【逆序偶+归并排序】
1019 逆序数 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序.一个排列中逆序的总数就称为这个排列的逆序数. 如2 4 3 1中,2 1,4 3, ...
- 矩阵分析:广义逆矩阵,{1}逆,MP逆,D逆
1,广义逆矩阵 设 满足下列四个 方程: (1)(2) (3)(4) 的某个几个或全部,则称 为 的广义逆矩阵. 满足全部四个方程的广义逆矩阵 称为 的 逆(存在且唯一). 设 ,若 ...
- (数学概念)矩阵的逆、伪逆、左右逆,最小二乘,投影矩阵
主要内容: 矩阵的逆.伪逆.左右逆 矩阵的左逆与最小二乘 左右逆与投影矩阵 一.矩阵的逆.伪逆.左右逆 1.矩阵的逆 定义: 设A是数域上的一个n阶方阵,若在相同数域上存在另一个n阶矩阵B,使得: A ...
- 线性代数学习笔记10-4:左右逆、伪逆/M-P广义逆(从四个子空间和SVD角度理解)
下面讨论m×nm\times nm×n的秩为rrr的矩阵 对于不同情况,讨论逆矩阵 两侧逆矩阵 2-sided inverse 这也是一般所说的"逆矩阵"的含义 方阵A\bolds ...
- 逆序输出三位数python_逆的部首|逆的拼音|逆的组词|逆的意思 - 查字典
逆 nì 拼音: nì 注音: ㄋㄧˋ 部首笔划:3 总笔划:9 繁体字:逆 汉字结构:半包围结构 简体部首:辶 造字法:形声 笔顺:捺撇横折竖撇捺折捺 逆的意思.基本信息 五笔86:UBTP 五笔9 ...
- 字符串逆序+单词逆序
字符串逆序+单词逆序 文章目录 字符串逆序+单词逆序 一.字符串逆序 二.单词逆序 三.感谢以及交流 一.字符串逆序 问题描述: 输入一个字符串arr,将其内容颠倒过来,并输出. 数据范围0<l ...
最新文章
- 《中国大数据产业白皮书及百强榜单》:一览中国大数据产业发展全局
- 解析三层架构(1)---为什么要分层?
- 洛谷P2068 统计和题解
- PyCharm的配置与安装
- Golang 的字符编码与 regexp
- Windows Server 2012改造成Windows8的方法(转载)
- python编码效率高吗_【原创】杠精的日常-讨论python快排的效率
- SVN客户端--TortoiseSVN使用说明
- Git submodule 的笔记
- 很久以前的C语言笔记
- CSS隐藏内容的三种方法比较
- 如何查看某个查询用了多少TempDB空间
- PHP 霸主地位被动摇,JIT 是穷途末路后的绝地反击?
- 数据结构作业——ギリギリ eye(贪心+优先队列/贪心+并查集)
- 中国电子学会c语言考试题库,计算机基础考试试题及答案
- 最详细的Android SDK下载安装及配置教程
- simulink如何更新版本的文件(mdl或slx),How to load models created with a newer version of Simulink
- android没有apk文件怎么打开方式,ios怎么打开apk文件,安卓无法打开apk文件
- 2022「博客新星」年度评选TOP100名单
- HTML压缩(JSP的GZIP实现)
热门文章
- java项目类上有黑色的点_图像处理 – 如何使用javacv / opencv识别黑色多边形上的点?...
- android选择多个文件_一分钟合并多个Excel、PDF文件,3种方法任你选择,好用到没朋友...
- datagridview选中获取行号_DataGridView控件显示行号的正确代码及分析
- python数据分析简答题_Python数据分析与数据可视化-中国大学mooc-试题题目及答案...
- windows如何生成ssh密钥
- BugkuCTF-MISC题蜜雪冰城~
- android 标题栏进度圈使用方法,Android 自定义标题栏 显示网页加载进度的方法实例...
- 虚拟机linux中怎样打开qt,虚拟机中在Centos 4.7中安装qt-x11-opensource-4.4.3
- shell mysql eof_shell EOF
- 单片机拼字程序怎么做_餐饮怎么用微信小程序?餐饮行业怎么做小程序