【剑指offer】面试题51:数组中的逆序对

题目

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

思路

1、暴力 ,时间复杂度O(n^2)

2、归并排序的思路 :时间复杂度O(nlogn)

* (1) 先将数组分成两半,递归分别计算左半边的逆序对数目leftCnt 和右半边的逆序对数目rightCnt
* (2)再计算合并之后新增的逆序对数目cnt

注意:
* left + right + cnt 有可能超过int,因此中间结果用long存储,最后再转化为int

代码

 1 public class P51 {
 2      // 归并排序 的变形
 3     private long mergeSort(int[] datas, int[] copy, int start, int end){
 4         if(start == end) return 0;
 5         int mid = (start + end)/2;
 6         long leftCnt = mergeSort(datas, copy, start, mid)%1000000007;// 左边的逆序对数目
 7         long rightCnt = mergeSort(datas, copy, mid+1, end)%1000000007; // 右边的逆序对数目
 8
 9         long cnt = 0;    // 合并之后,新增的逆序对数目
10         int index = start;    // copy数组的下标
11         int i = start;    // 左半边 数组起始下标
12         int j = mid+1;    // 右半边 数组起始下标
13
14         // 该变量记录当左半边某个数datas[i]插入copy数组中,右半边已经插入copy数组中的数目
15         int rightSmallICnt = 0;
16
17         // 合并数组,合并的时候计算逆序对数目
18         while(i<=mid && j<=end){
19             if(datas[i]<=datas[j]){
20                 copy[index++] = datas[i];
21                 i++;
22                 cnt += rightSmallICnt;
23             }else{
24                 copy[index++] = datas[j];
25                 j++;
26                 rightSmallICnt++;    // 记录右半边数组中右多少个元素 已经插入到copy数组中
27             }
28         }
29         if(i>mid){
30             while(j<=end){
31                 copy[index++] = datas[j++];
32             }
33         }else{
34             while(i<=mid){
35                 copy[index++] = datas[i++];
36                 cnt += rightSmallICnt;
37             }
38         }
39
40         // 复制回原数组
41         for(int k=start;k<=end;++k) datas[k] = copy[k];
42         return (leftCnt + rightCnt + cnt)%1000000007;
43     }
44
45     // 统计逆序对数目
46     public int InversePairs(int [] array) {
47         if(array==null || array.length<=1) return 0;    // 对输入数据进行处理
48         int[] copy = new int[array.length];                // 辅助数组
49         return (int)mergeSort(array, copy, 0, array.length-1);
50     }
51
52     // 测试
53     public static void main(String[] args) {
54         int[] array = new int[]{5,6,7,8, 1, 2, 3, 4};
55         int ans = new P51().InversePairs(array);
56         System.out.println(ans);
57     }
58 }

 

原文地址:https://www.cnblogs.com/chsobin/p/10585656.html

时间: 2024-11-05 22:40:08

【剑指offer】面试题51:数组中的逆序对的相关文章

剑指offer 面试题36—数组中的逆序对

题目: 在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数.例如在数组{7,5,6,4}中一共存在5对逆序对,分别是(7,6),(7,5),(7,4),(6,4),(5,4) 基本思想: 解法一:O(n^2) 最简单的想法就是遍历每一个元素,让其与后面的元素对比,如果大于则count++,但是这样的时间复杂度是O(n^2). 解法二:O(nlogn) 归并排序思路: 例如7,5,4,6可以划分为两段7,5和4,6两个子数组 1

剑指offer系列源码-数组中的逆序对

题目1348:数组中的逆序对 时间限制:1 秒内存限制:32 兆特殊判题:否提交:2133解决:500 题目描述: 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数. 输入: 每个测试案例包括两行: 第一行包含一个整数n,表示数组中的元素个数.其中1 <= n <= 10^5. 第二行包含n个整数,每个数组均为int类型. 输出: 对应每个测试案例,输出一个整数,表示数组中的逆序对的总数. 样例输入: 4 7 5 6 4

【剑指offer】题目36 数组中的逆序对

数组中任取两个数字,如果前面的数字大于后面的数字称为一个逆序对 如:1,2,1,2,1 有3个逆序对 思路:知道O(N2)肯定是错的.开始想hash,试图找到O(n)的算法,想了很久,找不到.后来想到排序,用原数组与排好序的数组对比,我写的快排,还是不对.想了几个小时,无奈看答案,原来是用变形的归并排序.排序真是博大精深,换个样子我就想不到了.... 在牛客网上AC的代码:脑子不清醒,各种小错,提交了好多遍. class Solution { public: void myMergeSort(v

剑指offer 面试题40—数组中两个只出现一次的数字

题目: 一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字.要求时间复杂度O(n),空间复杂度O(1). 基本思想: http://blog.csdn.net/wtyvhreal/article/details/44260321 #include <iostream> using namespace std; int Find1(int n)//从低位开始找第一个1的位置 { int index=0; while((n&1)==0 &&a

【剑指offer】Q29:数组中出现次数超过一半的数字

就本题而言,个人觉得练习下partition函数是有必要的,毕竟它是快速排序的核心,是基础性的东西,也是必须要掌握的,至于书中给出的"取巧"性解法,是属于个人思维能力的考察,是一种考虑问题的思路,不是一两个问题就能练就的. partition函数,包括快速排序,是一定要信手拈来的,必须的. import random def MoreThanHalf(array): if len(array) == 0: return 0 start = 0 end = len(array) - 1

【剑指offer】二维数组中的查找

题目描述: 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 分析: 首先选择数组中右上角的数字.如果该数字等于要查找的数字,查找过程结束:如果该数字大于要查找的数字,剔除这个数字所在的列:如果该数字小于要查找的数字,剔除这个数字所在的行.依次类推,直到查找范围为空. 示例程序: #include <stdio.h> #include <stdlib.h> int

剑指OFFER之二维数组中的查找(九度OJ1384)

题目描述: 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 输入: 输入可能包含多个测试样例,对于每个测试案例, 输入的第一行为两个整数m和n(1<=m,n<=1000):代表将要输入的矩阵的行数和列数. 输入的第二行包括一个整数t(1<=t<=1000000):代表要查找的数字. 接下来的m行,每行有n个数,代表题目所给出的m行n列的矩阵(矩阵如题目描述所示,每

【剑指offer】Q40:数组中出现一次的数字

按着书里面讲述的方法,根据某一位来将整个数组拆分成两个部分,取每一部分中出现一次的数.书中的处理略显复杂,这里简化下分类的方法. def once(array): reOR = 0 for x in array: reOR ^= x bit1 = firstBit1(reOR) first = 0 second = 0 for x in array: if x & bit1 != 0: first ^= x else: second ^= x return first, second def f

【剑指offer】Q40:数组中出现一次的数

书里面关于分类的判断有些麻烦,通过某一位为0为1来对数组元素进行分类.假如第3位为1,那么也就是元素x & 8 等于或不等于0,所以没必要非的用第几位去判断. def once(array): reOR = 0 for x in array: reOR ^= x bit1 = firstBit1(reOR) first = 0 second = 0 for x in array: if x & bit1 != 0: first ^= x else: second ^= x return f

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

本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数. 思路 如果遍历数组,对每个数字都和后面的数字比较大小,时间复杂度为O(n^2),效率太低. 利用归并排序的思想,先将数组分解成为n个长度为1的子数组,然后进行两两合并同时排好顺序. 在对两个子区域合并排序时,记左边区域(下标为start~mid)的指针