首页 > 编程语言 >剑指offer(Java)-数组中的逆序对(困难)

剑指offer(Java)-数组中的逆序对(困难)

时间:2023-04-03 22:34:50浏览次数:55  
标签:right Java offer int nums 数组 left 逆序

题目:

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。

示例1:

输入: [7,5,6,4]

输出: 5

限制:

0 <= 数组长度 <= 50000

解题思路:

这道题的核心在于 归并排序,在归并排序的基础上进行求解 逆序对。

题解参考 K神老师的题解 和  liweiwei1419老师的讲解视频,这道题对于我来说有点困难~

归并排序的核心在于分治思想:

  • 分: 不断将数组从中点位置划分开(即二分法),将整个数组的排序问题转化为子数组的排序问题;
  • 治: 划分到子数组长度为 1 时,开始向上合并,不断将 较短排序数组 合并为 较长排序数组,直至合并至原数组时完成排序。

大致思想:

主函数reversePairs():

1.执行差分数组方法mergeSort()

2.返回逆序对总数

差分数组mergeSort():

1.将数组一份为二,进行递归拆分;

2.执行归并排序merge(),并统计逆序对的个数。

 归并排序merge():

1.定义一个临时数组,用于统计合并过程中的临时数组;

2.设置双指针 i 和 j 分别指向左右子数组的首元素即 i = left , j = mid+1,设置t=0指向临时数组下标:

  • nums[i] <= nums[j]:说明左子数组的元素小于右子数组,此时不存在逆序对,直接将nums[i]放入temps[t],执行 i++,j++;(类似于下图情况)

  • 否则 nums[i] > nums[j]:说明左子数组及左子数组剩下的元素都大于右子数组元素,则将小的nums[j]放入temps[t],并执行j++,t++,逆序数对数加 m-i+1个(类似于下图情况)

  • 当 i <= mid 时(j > right),代表右子数组已经合并完,剩余的左子数组加入到temp后面即可;
  • 当 j <= right 时(i>mid),代表左子数组已经合并完,剩余的右子数组加入到temp后面即可。

  •  最后需要将每一轮排好序的数组放回原数组。

疑惑:nums[left + k] = temp[k]:因为合并方法merge()中的left根据每一次递归都不一样的,故每一次排好序的数都应该从left开始放。

代码:

 1 class Solution {
 2     //定义一个全局变量用于计算逆序对的个数
 3     int count = 0;
 4     public int reversePairs(int[] nums) {
 5         mergeSort(nums, 0, nums.length-1);
 6         return count;   
 7     }
 8     //将数组拆分
 9     public void mergeSort(int[] nums,int left,int right){
10         //如果只有一个或空则直接退出
11         if (left >= right) return;
12         int mid = (left + right) /2;
13         //对左边进行拆分
14         mergeSort(nums, left, mid);
15         //对右边进行拆分
16         mergeSort(nums, mid+1, right);
17         //合并
18         merge(nums,left,right,mid);
19     }
20     //合并方法
21     public void merge(int[] nums,int left,int right,int mid){
22         //定义一个临时数组
23         int[] temp = new int[right-left+1];
24         //定义指针指向第一个数组的第一个元素
25         int i = left;
26         //定义指针指向第二个数组的第一个元素
27         int j = mid+1;
28         //定义一个指针指向临时数组的第一个元素
29         int t = 0;
30         //当两数组都有数据的时候进行遍历
31         while (i <= mid && j <= right){
32             //如果第一个数组元素小,那么就直接将小的放入临时数组
33             if(nums[i] <= nums[j]){
34                 temp[t++] = nums[i++];
35             }else{
36                 //如果第一个数组元素大,那么就要将小的先放,并统计逆序对的个数
37                 count += mid-i+1;
38                 temp[t++] = nums[j++];
39             }
40         }
41         //当右边的数组已经遍历完,左边还剩余的时候,直接将剩余元素加入临时数组
42         while (i <= mid){
43             temp[t++] = nums[i++];
44         }
45         //当左边的数组已经遍历完,右边还剩余的时候,直接将剩余元素加入临时数组
46         while (j <= right){
47             temp[t++] = nums[j++];
48         }
49         //用临时数组的值去覆盖原数组的值
50         for(int k = 0; k < temp.length; k++){
51             nums[left + k] = temp[k];
52         }
53     }
54 }

 

标签:right,Java,offer,int,nums,数组,left,逆序
From: https://www.cnblogs.com/liu-myu/p/17282160.html

相关文章

  • 【Java 并发】【八】【Atomic】【一】JUC下的Atomic原子类体系概览
    1 前言这节我们就开始看看Atomic原子类系列,JUC包下提供的原子类底层的实现原理基本都是差不多的,都是基于volatile和CAS操作来保证线程安全的,我们后续会着重分析几个类。2  概览我们看下JUC下边都有哪些原子类:看上面的图形,我们使用红色圈中的那些,就是我们要着重讨论的,一共......
  • Java-Day-3(运算符 + 标识符 + 键盘输入)
    Java-Day-3运算符算术运算符关系运算符[比较运算符]逻辑运算符赋值运算符三元运算符位运算符[需要二进制基础]算术运算符+、-、*、/System.out.println(10.0/4);//2.5doubled=10/4;//2.0//数学公式有时不能硬搬,例如:摄氏温度=5/9*(华氏温......
  • 【专题】排列逆序数的奇偶性
    排列逆序数的奇偶性是一个十分常见的属性。不同于直接求逆序数,由于排列的性质,这玩意是可以\(\mathcalO(n)\)直接求解的。为了完成这一点,引入如下基本结论:排列两元素对换,逆序数奇偶性改变。排列的逆序数同余\(n-\#\)环。第一点,在大多数线性代数教材中都有所提及。第二......
  • 1006-HBase操作实战(JAVA API模式)
    一、准备阶段开发环境:hadoop: hadoop -2.4.0hbase: hbase -0.94.11-securityeclipse:JunoServiceRelease2二、创建 hbasedemo项目1、通过Eclipse创建一个新Java工程2、右击项目根目录,选择“Propertiesà>JavaBuildPathà>Libraryà> Add Ext......
  • 如何使用Java程序实现二叉数
    二叉树是一种重要的数据结构,它由一组节点组成,每个节点可以拥有最多两个子节点。使用Java可以很容易地实现一个二叉树。下面将介绍如何使用Java实现二叉树。二叉树的节点定义一个二叉树的节点可以定义为一个类,其中至少需要包含以下属性:节点值左子节点右子节点在Java中,我们......
  • Java多线程
    1.可见性、原子性和有序性问题多线程有三大特性,分别是可见性、原子性和有序性。1.1可见性  在单核时代,所有的线程都是在一颗CPU上执行,CPU缓存与内存的数据一致性容易解决。因为所有线程都是操作同一个CPU的缓存,一个线程对缓存的写,对另外一个线程来说一定是可见的。一个线程......
  • Java判断文件夹、文件是否存在,不存在则新建
    Java判断文件夹、文件是否存在,不存在则新建原文链接:https://blog.csdn.net/asfsdgdfgdf/article/details/1283162781、Java判断是否存在文件夹,不存在则新建Filefile=newFile("D:/test/filetest/test.txt");if(!file.getParentFile().exists()){file.getParentFile().......
  • Java 获取当前或调用者类名和方法名(Thread.currentThread().getStackTrace()、new Thr
    Java获取当前或调用者类名和方法名(Thread.currentThread().getStackTrace()、newThrowable().getStackTrace())原文链接:https://blog.csdn.net/inthat/article/details/111885544文章目录一、Java获取当前类名和方法名Thread.currentThread().getStackTrace()1.关于Thr......
  • 2-Java基础语法
    1.注释注释是对代码的解释和说明文字。Java中的注释分为三种:单行注释://这是单行注释文字多行注释:/_这是多行注释文字这是多行注释文字这是多行注释文字_/注意:多行注释不能嵌套使用。文档注释(暂时用不到):/*_这是多行注释文字这是多行注释文字这是多......
  • 如何用Java程序生成大乐透号码?
    在大乐透游戏中,需要选出5个红球号码和2个蓝球号码。这个过程可能比较耗时,而且如果想要生成多组号码,手动输入的方式就变得特别不切实际。因此,我们可以使用Java程序来实现大乐透号码的自动生成。一、生成红球号码首先,需要确定生成红球号码的范围和数量。在大乐透游戏中,红球号码的......