剑指 Offer 51. 数组中的逆序对

Offer_51

题目描述

方法一:暴力法(双层循环,超时)

package com.walegarrett.offer;

/**
* @Author WaleGarrett
* @Date 2021/2/9 9:12
*/ /**
* 题目详情:在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。
* 输入一个数组,求出这个数组中的逆序对的总数。
*/ import java.util.Arrays; /**
* 方法一:暴力解法(超时TLE)
*/
public class Offer_51 {
public int reversePairs(int[] nums) {
int len = nums.length;
int cnt = 0;
for(int i=0; i<len; i++){
int now = nums[i];
for(int j=0;j<i;j++){
if(nums[j] > now)
cnt++;
}
}
return cnt;
}
}

方法二:归并排序法

/**

 * 方法二:归并排序
*/
class Offer_51_2 {
public int reversePairs(int[] nums) {
int len = nums.length;
if(len < 2)
return 0;
int[] second = Arrays.copyOf(nums, len);
return reversePairs(nums, 0, len-1, new int[len]);
}
int reversePairs(int[] nums, int left, int right, int[] tmp){
if(left == right)
return 0;
int mid = (left + right) >> 1;
int leftCnt = reversePairs(nums, left, mid, tmp);
int rightCnt = reversePairs(nums, mid+1, right, tmp);
//左半部分的最大值小于右半部分的最小值,所以这两部分的和没有逆序数对
if(nums[mid] <= nums[mid+1])
return leftCnt + rightCnt;
int crossCnt = mergeAndCount(nums, left, right, tmp);
return leftCnt + rightCnt + crossCnt;
}
//合并并统计逆序数
int mergeAndCount(int[] nums, int left, int right, int[] tmp){
for(int i=left;i<=right;i++){
tmp[i] = nums[i];
}
int mid = (left + right) >> 1;
int cnt = 0;
int i = left;
int j = mid+1;
for(int k=left; k<=right; k++){
if(i == mid+1){
nums[k] = tmp[j];
j++;
}else if(j == right+1){
nums[k] = tmp[i];
i++;
}else if(tmp[i] <= tmp[j]){//左指针右移
nums[k] = tmp[i];
i++;
}else{//右指针右移
nums[k] = tmp[j];
j++;
cnt += (mid-i+1);
}
}
return cnt;
}
}

方法三:树状数组

/**

 * 方法三:树状数组
*/
//树状数组
class BIT{
int[] tree;
int n;
public BIT(int n){
this.n = n;
this.tree = new int[n+1];
} public static int lowbit(int x){
return x&(-x);
}
public void update(int i){
while(i<=n){
++ tree[i];
i += lowbit(i);
}
}
public int query(int i){
int cnt = 0;
while(i!=0){
cnt += tree[i];
i -= lowbit(i);
}
return cnt;
}
}
class Offer_51_3 {
public int reversePairs(int[] nums) {
int len = nums.length;
int[] tmp = new int[len];
tmp = Arrays.copyOf(nums, len);
//离散化:获取元素之间的相对排名
Arrays.sort(tmp);
for(int i=0; i<len; i++){
nums[i] = Arrays.binarySearch(tmp, nums[i]) + 1;
}
BIT bit = new BIT(len);
int ans = 0;
for(int i = len-1; i>=0; i--){
ans+=bit.query(nums[i] - 1);
bit.update(nums[i]);
}
return ans;
}
}

参考题解:数组中的逆序对

剑指 Offer 51. 数组中的逆序对 + 归并排序 + 树状数组的更多相关文章

  1. [剑指offer]51-数组中的逆序对(归并排序)

    题目链接 https://www.nowcoder.com/questionTerminal/96bd6684e04a44eb80e6a68efc0ec6c5 题意 在数组中的两个数字,如果前面一个数 ...

  2. AcWing 107. 超快速排序(归并排序 + 逆序对 or 树状数组)

    在这个问题中,您必须分析特定的排序算法----超快速排序. 该算法通过交换两个相邻的序列元素来处理n个不同整数的序列,直到序列按升序排序. 对于输入序列9 1 0 5 4,超快速排序生成输出0 1 4 ...

  3. 力扣Leetcode 面试题51. 数组中的逆序对 - 归并排序

    在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数. 示例 1: 输入: [7,5,6,4] 输出: 5 限制: 0 <= ...

  4. 九度OJ 1348 数组中的逆序对 -- 归并排序

    题目地址:http://ac.jobdu.com/problem.php?pid=1348 题目描述: 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求 ...

  5. 51nod1019逆序数(归并排序/树状数组)

    题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1019 题意:中文题诶- 思路: 方法1:归并排序- 归并排序过 ...

  6. 【BZOJ 3295】动态逆序对 - 分块+树状数组

    题目描述 给定一个1~n的序列,然后m次删除元素,每次删除之前询问逆序对的个数. 分析:分块+树状数组 (PS:本题的CDQ分治解法见下一篇) 首先将序列分成T块,每一块开一个树状数组,并且先把最初的 ...

  7. Bzoj 3295: [Cqoi2011]动态逆序对 分块,树状数组,逆序对

    3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2886  Solved: 924[Submit][Stat ...

  8. Day2:T4求逆序对(树状数组+归并排序)

    T4: 求逆序对 A[I]为前缀和 推导 (A[J]-A[I])/(J-I)>=M A[j]-A[I]>=M(J-I) A[J]-M*J>=A[I]-M*I 设B[]=A[]-M*( ...

  9. bzoj3295 [Cqoi2011]动态逆序对 cdq+树状数组

    [bzoj3295][Cqoi2011]动态逆序对 2014年6月17日4,7954 Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数. ...

随机推荐

  1. 【uva 10954】Add All(算法效率--Huffman编码+优先队列)

    题意:有N个数,每次选2个数合并为1个数,操作的开销就是这个新的数.直到只剩下1个数,问最小总开销. 解法:合并的操作可以转化为二叉树上的操作[建模],每次选两棵根树合并成一棵新树,新树的根权值等于两 ...

  2. - Visible Trees HDU - 2841 容斥原理

    题意: 给你一个n*m的矩形,在1到m行,和1到n列上都有一棵树,问你站在(0,0)位置能看到多少棵树 题解: 用(x,y)表示某棵树的位置,那么只要x与y互质,那么这棵树就能被看到.不互质的话说明前 ...

  3. Codeforces Round #529 (Div. 3) D. Circular Dance (思维)

    题意:有\(n\)个熊小孩,绕着树转圈圈,编号\(i\)的小孩可以记住\(a_{i,1}\)和\(a_{i,2}\)两个小孩,这两个小孩是顺时针相邻的,但谁前谁后不一定.现在给你每个小孩的\(a_{i ...

  4. dart类详细讲解

    dart 是一个面向对象的语言;面向对象有 (1)继承 (2)封装 (3)多态 dart的所有东西都是对象,所有的对象都是继承与object类 一个类通常是由属性和方法组成的哈: 在dart中如果你要 ...

  5. Operating System:信号量

    pv原语操作(1)操作系统PV意思:PV操作与信号量的处理相关,P表示通过的意度思,V表示释放的意思.(2)p操作和v操作是不可中断问的程序段,称为原语.如果将信号量看作共享变量,则pv操作为其临界区 ...

  6. ES6 Set All In One

    ES6 Set All In One Set 集合 Map 字典/地图 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Referenc ...

  7. 如何给 GitHub 添加 SSH key, 如何生成 SSH key 详细图文教程!

    如何给 GitHub 添加  SSH key, 如何生成  SSH key 详细图文教程! 一. 生成  SSH key https://ide.c9.io/xgqfrms/ 创建一个空项目:(或使用 ...

  8. 使用 js 实现一个简易版的 drag & drop 库

    使用 js 实现一个简易版的 drag & drop 库 具有挑战性的前端面试题 H5 DnD js refs https://www.infoq.cn/article/0NUjpxGrqRX ...

  9. 神奇的数学学习网站 All In One

    神奇的数学学习网站 All In One magical math websites {{uploading-image-923797.png(uploading...)}} Math is Fun ...

  10. window.locationbar

    window.locationbar demo https://cdn.xgqfrms.xyz/#/operate-tool/select-seat-system/select-detail?temp ...