题目:

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

示例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 }

剑指offer51(Java)-数组中的逆序对(困难)的更多相关文章

  1. 剑指 Offer 51. 数组中的逆序对 + 归并排序 + 树状数组

    剑指 Offer 51. 数组中的逆序对 Offer_51 题目描述 方法一:暴力法(双层循环,超时) package com.walegarrett.offer; /** * @Author Wal ...

  2. 【Java】 剑指offer(51)数组中的逆序对

    本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组成 ...

  3. 【剑指offer】数组中的逆序对

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/mmc_maodun/article/details/27520535 转载请注明出处:http:// ...

  4. 剑指offer-36:数组中的逆序对

    参考:1. https://www.geeksforgeeks.org/merge-sort/ 2.<剑指Offer:名企面试官精讲典型编程题> 题目描述 在数组中的两个数字,如果前面一个 ...

  5. Go语言实现:【剑指offer】数组中的逆序对

    该题目来源于牛客网<剑指offer>专题. 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数P.并将P对10000 ...

  6. 剑指Offer 35. 数组中的逆序对 (数组)

    题目描述 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数P.并将P对1000000007取模的结果输出. 即输出P%1000 ...

  7. 【剑指offer】数组中的逆序对。C++实现

    原创文章,转载请注明出处! 博客文章索引地址 博客文章中代码的github地址 # 题目 # 思路 基于归并排序的思想统计逆序对:先把数组分割成子数组,再子数组合并的过程中统计逆序对的数目.统计逆序对 ...

  8. [剑指Offer] 35.数组中的逆序对

    题目描述 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数P.并将P对1000000007取模的结果输出. 即输出P%1000 ...

  9. 剑指offer:数组中的逆序对

    题目描述: 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数P.并将P对1000000007取模的结果输出. 即输出P%100 ...

  10. 剑指offer35:数组中的逆序对

    1 题目描述 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数P.并将P对1000000007取模的结果输出. 即输出P%10 ...

随机推荐

  1. 汽车VR虚拟仿真技术如何加速自动驾驶的发展?

    虚拟现实和虚拟仿真将带领自动驾驶汽车从汽车研发.体验.展厅.销售等各个环节迈入全新时代.2019 年,全球增强现实和虚拟现实市场为168 亿美元,到 2023 年,该市场的未来增长预计将超过 1600 ...

  2. 三维模型3DTile格式轻量化顶点压缩主要技术方法分析

    三维模型3DTile格式轻量化顶点压缩主要技术方法分析 三维模型顶点压缩是3DTile格式轻量化压缩的重要组成部分,能有效减小数据大小,提高数据处理效率.下面将详细分析几种主要的顶点压缩技术方法: 预 ...

  3. 【已失效】Xcode GUI 添加 SPM 依赖的时候访问不了 github,无视 git config proxy 配置解决方案

    此 openradar 中提出者指出了原因:Xcode 调用 libgit2 时传入了 GIT_PROXY_NONE,无视了 git config 中的 proxy 配置.作者说用了自己打的 libg ...

  4. 开发必会系列:hibernate事务

    一  事务定义及特性 1.数据库事务的定义:数据库事务(Database Transaction) 是指由一个或多个SQL语句组成的工作单元,这个工作单元中的SQL语句相互依赖,如果有一个SQL语句执 ...

  5. 使用SpringBatch读取csv文件

    目录 1.需求 2.解决方案 3.注意事项 1.文件路径的获取 2.各个Step如果获取到ExecutionContext中的值 3.FlatFileItemReader使用注意 4.实现步骤 1.导 ...

  6. vue中elementui组件el-dialog拖拽(已处理边界情况)

    全局注册 Vue.directive("elDialogDrag", (el) => { const header = el.querySelector(".el- ...

  7. Docker部署之使用docker-compose部署(全新的干净的服务器,从0开始搭建)

    部署环境准备 安装yum # 安装yum工具 yum install -y yum-utils device-mapper-persistent-data lvm2 --skip-broken 安装d ...

  8. SQL优化篇之-如何减少耗时查询的调用次数

    函数调用次数与性能 在查询语句中,如果 Select 子句调用了较为耗时的函数或子查询,需要特别考虑函数调用次数对于SQL整体执行时间的影响. 一.数据准备,SQL 语句 模拟较耗时的用户函数 确保执 ...

  9. CSS样式中的各种居中方式

    1.水平居中 将margin-left和margin-right属性设置为auto,从而达到水平居中的效果. 代码: margin:0 auto; 2.文字水平垂直居中 利用line-height设为 ...

  10. Impala 高性能、低延迟的大数据查询引擎

    Impala是什么? Impala提供对大数据更快速,交互式 SQL查询. Impala支持对存储在HDFS.HBase及S3等数据查询. Impala使用和Hive相同的元数据.SQL定义.ODBC ...