逆序对计数问题(java实现)
一,相关定义
1.什么是逆序数?
在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。
例如:在序列 { 2, 4, 3, 1 } 中,逆序依次为 (2,1),(4,3),(4,1),(3,1),因此该序列的逆序数为 4。
2.什么是逆序对?
如果存在正整数 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个。
一个排列的逆序对的总数就是该排列的逆序数。(本质上逆序数和逆序对都是一样的)
二,问题描述
给定一个数组,求该数组中包含多少个逆序对。
三,求解方法
1.方法一:最原始的方法,利用两重循环进行枚举。该算法的时间复杂度为O()。
import java.util.Scanner;
public class mod2{public static void main(String[] args){Scanner sc=new Scanner(System.in);int []arr= new int[30];System.out.print("请输入数组元素个数:");int number=sc.nextInt();System.out.print("请输入数组元素:");for(int i=0;i<number;i++) {arr[i]=sc.nextInt();}int count=0;for(int i=0;i<number;i++){for(int j=i+1;j<number;j++){if(arr[i]>arr[j]){count+=1;}}}System.out.println("逆序对的数目为:"+count);}
}
2.方法二:利用归并排序的思想求解逆序对的个数,这是解决该问题的一种较为高效的算法。该算法的时间复杂度为O(nlogn)。
具体解法可以参考一下b站LeetCode的视频,讲的非常详细。
《剑指 Offer》 51. 数组中的逆序对【LeetCode 力扣官方题解】
就是在归并排序合并的同时进行计数这么个道理。
3.方法三:利用树状数组求逆序对,开始先将序列离散化以提高算法的时空效率,然后从序列的最左端开始建立树状数组,每创建一个就执行一次 i - getsum( x ) (x 为离散化的 值) 累加到ans上。最后的 ans即为所求的答案。注意在进行排序的时候如果两个数组的值相等, 则需要确保排序后原先的相对顺序不发生改变, 即确保使用稳定的排序方式。
四,方法二代码及调试
第一次测试
public class mod3{public int reversePairs(int[] arr){if(arr.length<2){return 0;}//判断数组中是否有元素,或者仅有一个元素,不存在有序对int[] temp=new int[arr.length];//建立一个临时变量数组return reversePairs(arr,0,arr.length-1,temp);//开始进行递归}public int reversePairs(int[] arr,int left,int right,int[] temp){if(left==right){return arr[left];}//递归出口int mid=left+(right-left)/2;int leftPairs=reversePairs(arr,left,mid,temp);//左半部分的逆序对个数int rightPairs=reversePairs(arr,mid+1,right,temp);//右半部分的逆序对个数int crossPairs=mergePairs(arr,left,mid,right,temp);//跨中点的逆序对个数return leftPairs+rightPairs+crossPairs;//逆序对个数总和}public int mergePairs(int[] arr,int left,int mid,int right,int[] temp){int i=left,j=mid+1,k=left,count=0;while(i<=mid&&j<=right){if(arr[i]>=arr[j]){temp[k]=arr[j];j++;k++;count+=mid-i+1;}else{temp[k]=arr[i];i++;k++;}}if(i==mid+1){for(k=k-1;k<=right;k++){temp[k]=arr[j];}}if(j==right+1){for(k=k-1;k<=right;k++){temp[k]=arr[i];}}return count;}public static void main(String[] args){mod3 solution=new mod3();int[] arr={3,1,4,5,2};int finall=solution.reversePairs(arr);System.out.println("该数组逆序对的个数为 :"+finall);}
}
输出结果为17,原因不明。
第二次测试
修改了temp数组和arr数组判定和赋值位置,我发现如果不修改,就没法实现递归下让序列变得有序,但是输出结果仍为17,后经检查得知错误出在递归出口处返回的值是数组元素值,而不是0。
应该让每次出口处返回0,而完成递归后返回三个逆序对个数总和。
public class mod3{public int reversePairs(int[] arr){if(arr.length<2){return 0;}//判断数组中是否有元素,或者仅有一个元素,不存在有序对int[] copy=arr.clone();int[] temp=new int[arr.length];//建立一个临时变量数组return reversePairs(copy,0,arr.length-1,temp);//开始进行递归}public int reversePairs(int[] arr,int left,int right,int[] temp){if(left==right){return arr[left];}//递归出口int mid=left+(right-left)/2;int leftPairs=reversePairs(arr,left,mid,temp);//左半部分的逆序对个数int rightPairs=reversePairs(arr,mid+1,right,temp);//右半部分的逆序对个数int crossPairs=mergePairs(arr,left,mid,right,temp);//跨中点的逆序对个数return leftPairs+rightPairs+crossPairs;//逆序对个数总和}public int mergePairs(int[] arr,int left,int mid,int right,int[] temp){int[] tempArr=arr.clone();int i=left,j=mid+1,k=left,count=0;while(i<=mid&&j<=right){if(tempArr[i]>=tempArr[j]){arr[k]=tempArr[j];j++;k++;count+=mid-i+1;}else{arr[k]=tempArr[i];i++;k++;}}if(i==mid+1){for(k=k-1;k<=right;k++){arr[k]=tempArr[j];}}if(j==right+1){for(k=k-1;k<=right;k++){arr[k]=tempArr[i];}}return count;}public static void main(String[] args){mod3 solution=new mod3();int[] arr={3,1,4,5,2};int finall=solution.reversePairs(arr);System.out.println("该数组逆序对的个数为 :"+finall);}
}
第三次测试
临时数组tempArr在对排序后剩余的左右数组中的元素进行归位的时候下标出现了问题,少了一位导致覆盖掉了一个元素。
if(i==mid+1){
for(; k<=right; k++){
arr[k]=tempArr[j];
}
}
if(j==right+1){
for(;k<=right;k++){
arr[k]=tempArr[i];
}
}
这里将k=k-1删掉就正常了。
最终完整代码
public class mod3{public int reversePairs(int[] arr){if(arr.length<2){return 0;}//判断数组中是否有元素,或者仅有一个元素,不存在有序对int[] copy=arr.clone();return reversePairs(copy,0,arr.length-1);//开始进行递归}public int reversePairs(int[] arr,int left,int right){if(left==right){return 0;}//递归出口int mid=left+(right-left)/2;int leftPairs=reversePairs(arr,left,mid);//左半部分的逆序对个数int rightPairs=reversePairs(arr,mid+1,right);//右半部分的逆序对个数int crossPairs=mergePairs(arr,left,mid,right);//跨中点的逆序对个数return leftPairs+rightPairs+crossPairs;//逆序对个数总和}public int mergePairs(int[] arr,int left,int mid,int right){int[] tempArr=arr.clone();int i=left,j=mid+1,k=left,count=0;while(i<=mid&&j<=right){if(tempArr[i]>=tempArr[j]){arr[k]=tempArr[j];j++;k++;count+=mid-i+1;}else{arr[k]=tempArr[i];i++;k++;}}if(i==mid+1){for(; k<=right; k++){arr[k]=tempArr[j];}}if(j==right+1){for(;k<=right;k++){arr[k]=tempArr[i];}}return count;}public static void main(String[] args){mod3 solution=new mod3();int[] arr={3,2,9,1};int finall=solution.reversePairs(arr);System.out.println("该数组逆序对的个数为 :"+finall);}
}
结果
逆序对百度百科
逆序对计数问题(java实现)相关推荐
- 蓝桥杯-逆序对(java)
算法训练 逆序对 时间限制:1.0s 内存限制:256.0MB 问题描述 Alice是一个让人非常愉跃的人!他总是去学习一些他不懂的问题,然后再想出许多稀奇古怪的题目.这几天,Alice又沉浸 ...
- 【LeetCode笔记】剑指Offer 51. 数组中的逆序对(Java、分治)
题目描述 多说无益-直接冲代码吧! 思路 && 代码 1. 暴力 O(n2n^2n2) 乍一看这题目,很难不直接用暴力法冲一冲(也就双层循环的事) 但是不出意料地超时啦-想一想,O(n ...
- 算法笔记_065:分治法求逆序对(Java)
目录 1 问题描述 2 解决方案 2.1 蛮力法 2.2 分治法(归并排序) 1 问题描述 给定一个随机数数组,求取这个数组中的逆序对总个数.要求时间效率尽可能高. 那么,何为逆序对? 引用自百度 ...
- 逆序对java_算法导论学习||查找逆序对
查找逆序对很简单,自己变成就是几行,思路也是十分简单.但是题目要求用递归的方法,和合并排序很相似,网上也有很多人提供具体的程序,但是我对这种递归排序还是不能清晰得理解,所以在这里就不贴出来了,只放上了 ...
- [剑指offer][JAVA]面试题[51][数组中的逆序对][归并排序]
[问题描述]面试题51.数组中的逆序对 (困难) 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数. 示例 1:输入: [7, ...
- 逆序对(洛谷P1908题题解,Java语言描述)
题目要求 题目链接 分析 逆序对这个说法我们在线性代数应该就接触过了吧,这里的逆序对应该与序偶也有关吧,总之简单点说就是顺序反了(相较于我们的比较标准)的一对数据. <1, 2, 3, 4, 5 ...
- java逆序对距离之和,七天刷完剑指offer-【第27道-第37道】
27.字符串的排列 1. 题目描述 输入一个字符串,按字典序打印出该字符串中字符的所有排列. 2. 示例 例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac, ...
- 剑指offer编程题(JAVA实现)——第35题:数组中的逆序对
github https://github.com/JasonZhangCauc/JZOffer 剑指offer编程题(JAVA实现)--第35题:数组中的逆序对 题目描述 在数组中的两个数字,如果前 ...
- [LeetCode][H0629]K个逆序对数组(Java)(动态规划)
题目描述 给出两个整数 n 和 k,找出所有包含从 1 到 n 的数字,且恰好拥有 k 个逆序对的不同的数组的个数. 逆序对的定义如下:对于数组的第i个和第 j个元素,如果满i < j且 a[i ...
最新文章
- [JS]题解 | #魔法数字#
- mysql 错误处理
- ftp上传当天文件的方法_五种方法将文件上传到FTP服务器
- 北斗导航 | 监测和减轻空间天气对GNSS应用的影响
- mogodbshell中数组对象查询修改方法
- 【Python】mayavi小结
- what's the difference between atime, ctime and mtime
- 视频封面自动播放两秒钟html,使用videojs轻松搭建一个播放器
- SQL Server 2014 新建数据库
- centos7 redis配置
- Java代码实现时钟
- 自学编程的5个技巧总结
- 高瓴张磊:从学渣到投资大佬,也曾多次犯错
- CSS3的clac()函数无效,警告提示“invalid property value”
- vs2008设置选中 高亮
- html英文颜色大全,html英文颜色名称全集
- Python爬虫实战(02)—— 爬取诗词名句三国演义
- Linux环境下搭建Apache服务器(完整版)
- Dynamo 如何生成管道
- 在计算机网络俗称网上邻居上能看到自己,为什么在“网上邻居”中可以看到自己,却看不到其他联网电脑?...
热门文章
- 马卡龙配色Icon·主题设计
- 坚持——我的朋友卢峰。
- pycharm 导入python环境
- RERAN:安卓系统的定时和点击的录制和回放——(5)
- 使用神卓互联内网穿透远程访问管家婆系统
- PMP证书的有效期是多久,怎么查验PMP证书有效性?
- Revit中墙体的连接方式创建,快速改变墙连接状态
- TabLayout使用介绍(com.google.android.material.tabs.TabLayout)
- 了解更多关于未删节有声读物
- 300行HTML+CSS+JS代码实现动态圣诞树