题目描述

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

输入描述:

题目保证输入的数组中没有的相同的数字
数据范围:
对于%50的数据,size<=10^4
对于%75的数据,size<=10^5
对于%100的数据,size<=2*10^5

示例:

输入:
{1, 2, 3, 4, 5, 6, 7, 0}
返回值:
7

解题思路及代码

方法一:暴力列举

暴力列举所有的数对,然后判断是否逆序。

具体方法是:按住一个arr[i], 依次判断{i+1 ... n-1]是否满足条件。n为数组的大小。

代码如下:

class Solution {private:const int kmod = 1000000007;
public:int InversePairs(vector<int> data) {int ret = 0;int n = data.size();for (int i = 0; i < n; ++i) {for (int j = i + 1; j < n; ++j) {if (data[i] > data[j]) {ret += 1;ret %= kmod;}}}return ret;}
};

对于10^5数据,O(N^2)算法显然超时。

时间复杂度:O(N^2)

空间复杂度:O(1)

方法二:归并排序思想

对数组一边进行归并排序,一边计算逆序对。

首先明确归并排序的过程:

  • 递归划分整个区间为基本相等的左右两个区间
  • 合并两个有序区间

归并排序的代码:

// 合并过程
void merge__(vector<int> &arr, int l, int mid, int r) {// 在这个地方创建额外空间,是一种不好的做法,更好的做法是:直接在最外层开辟一个足够大的数组,然后传引用到函数。vector<int> tmp(r - l + 1);int i = l, j = mid + 1, k = 0;while (i <= mid && j <= r) {if (arr[i] >= arr[j]) {tmp[k++] = arr[j++];}else {tmp[k++] = arr[i++];}}while (i <= mid) {tmp[k++] = arr[i++];}while (j <= r) {tmp[k++] = arr[j++];}for (k = 0, i = l; i <= r; ++i, ++k) {arr[i] = tmp[k];}
}// 递归划分过程
void merge_sort__(vector<int> &arr, int l, int r) {// 只有一个数字,则停止划分if (l >= r) {return;}int mid = l + ((r - l) >> 1);merge_sort__(arr, l, mid);merge_sort__(arr, mid + 1, r);// 合并两个有序区间merge__(arr, l, mid, r);
}
// 要排序的数组 arr
void merge_sort(vector<int>& arr) {merge_sort__(arr, 0, arr.size() - 1);
}

本题中如何利用归并排序的思想?

如果两个区间为[4, 3] 和[1, 2]

那么逆序数为(4,1),(4,2),(3,1),(3,2),同样的如果区间变为有序,比如[3,4] 和 [1,2]的结果是一样的,也就是说区间有序和无序结果是一样的。

但是如果区间有序会有什么好处吗?

当然,如果区间有序,比如[3,4] 和 [1,2]

如果3 > 1, 显然3后面的所有数都是大于1, 这里为 4 > 1, 明白其中的奥秘了吧。所以我们可以在合并的时候利用这个规则。

代码如下:

class Solution {private:const int kmod = 1000000007;
public:int InversePairs(vector<int> data) {int ret = 0;// 在最外层开辟数组vector<int> tmp(data.size());merge_sort__(data, tmp, 0, data.size() - 1, ret);return ret;}void merge_sort__(vector<int> &arr, vector<int> &tmp, int l, int r, int &ret) {if (l >= r) {return;}int mid = l + ((r - l) >> 1);merge_sort__(arr, tmp, l, mid, ret);merge_sort__(arr, tmp, mid + 1, r, ret);merge__(arr, tmp, l, mid, r, ret);}void merge__(vector<int> &arr, vector<int> &tmp, int l, int mid, int r, int &ret) {int i = l, j = mid + 1, k = 0;while (i <= mid && j <= r) {if (arr[i] > arr[j]) {tmp[k++] = arr[j++];// 奥妙之处ret += (mid - i + 1);ret %= kmod;}else {tmp[k++] = arr[i++];}}while (i <= mid) {tmp[k++] = arr[i++];}while (j <= r) {tmp[k++] = arr[j++];}for (k = 0, i = l; i <= r; ++i, ++k) {arr[i] = tmp[k];}}};

Java 版:

private long cnt = 0;
private int[] tmp;  // 在这里声明辅助数组,而不是在 merge() 递归函数中声明public int InversePairs(int[] nums) {tmp = new int[nums.length];mergeSort(nums, 0, nums.length - 1);return (int) (cnt % 1000000007);
}private void mergeSort(int[] nums, int l, int h) {if (h - l < 1)return;int m = l + (h - l) / 2;mergeSort(nums, l, m);mergeSort(nums, m + 1, h);merge(nums, l, m, h);
}private void merge(int[] nums, int l, int m, int h) {int i = l, j = m + 1, k = l;while (i <= m || j <= h) {if (i > m)tmp[k] = nums[j++];else if (j > h)tmp[k] = nums[i++];else if (nums[i] <= nums[j])tmp[k] = nums[i++];else {tmp[k] = nums[j++];this.cnt += m - i + 1;  // nums[i] > nums[j],说明 nums[i...mid] 都大于 nums[j]}k++;}for (k = l; k <= h; k++)nums[k] = tmp[k];
}

时间复杂度:O(NlogN)

空间复杂度:O(N)

解析参考来自:

数组中的逆序对_牛客网​www.nowcoder.com

vb.net中递归退到最外层_数组中的逆序对相关推荐

  1. vb.net中递归退到最外层_面试题被问到再也不慌,深究JavaScript中的深拷贝与浅拷贝...

    " 点个关注,养成习惯,带你python爬虫的过程中学习前端 " JavaScript中的深拷贝和浅拷贝是前端面试中频繁被问到的一道题, 于是我也自己去查阅了一些资料, 然后动手敲 ...

  2. js判断数组中重复元素并找出_面试中常遇见的数组去重

    导读 JS数组去重是面试中并不少见的问题,听起来很简单,当你兴高采烈地回答了你的方法之后,你以为这道题就结束了吗?No,一般来说,面试官会继续问你"除了你刚刚说的方法,还有其他更好的方法吗? ...

  3. mysql id 不在集合里面_MySQL,PHP:从表中选择*,其中id不在数组中

    所以我现在有一个数据库表,我试图选择所有记录,除了包含在我所做的数组中的所有记录.正如一些背景方面:MySQL,PHP:从表中选择*,其中id不在数组中 在有问题的数据库表的结构是: server_s ...

  4. 找出一个字符串中出现次数最多的字_海量数据中找出前k大数(topk问题)

    在海量数据中找出出现频率最好的前k个数,或者从海量数据中找出最大的前k个数,这类问题通常被称为top K问题. 针对top K类问题,通常比较好的方案是分治+Trie树/hash+小顶堆(就是上面提到 ...

  5. 地壳中元素含量排名记忆口诀_地壳中含量最多的元素是什么?地壳中元素含量排名口诀...

    地壳,乃地质术语,是指由岩石组成的固体地壳,是地球固体圈的最外层,也是岩石圈的重要组成部分.那么地壳中含量最多的元素是什么呢?以及地壳中元素含量排名口诀又是什么呢? 地壳中含量最多的元素 从地震波的研 ...

  6. java中json重复数据结构_JS实现去除数组中重复json的方法示例

    本文实例讲述了JS实现去除数组中重复json的方法.分享给大家供大家参考,具体如下: var array = [{"name":"123"},{"na ...

  7. VC++中从txt文本中读取数据并且存到二维数组中

    这几天因为在做作业,所以不仅会想到这一类有关的问题.现在我需要实现的是讲txt文件的数据读取出来并且存储到一个二维数组中.,首先为了对待什么样的矩阵我们都可以读取,我们就要设置一个动态的矩阵,这样当我 ...

  8. 剑指_数组中出现次数超过一半的数字

    题目描述 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2. ...

  9. 把txt中的数据读出并保存到数组中

    //以下代码演示如何把txt中的数据,读出并保存到数组中. #include <fstream> #include <stdio.h> #include <opencv2 ...

最新文章

  1. wget的url获取方式
  2. 网络安全对现在乃至以后,对人们的安全有着重大的保障
  3. 爬虫单个ip代理设置_爬虫怎么设置代理ip池?
  4. excel oledb mysql_OLEDB操作Excel
  5. Metasploit介绍
  6. 概率论与数理统计 (二)填空题
  7. PHP学习之十二:自定义函数
  8. Tensorflow实现VGG网络
  9. VassistX的简单介绍与下载安装
  10. 5G NR的调制方式与解调算法
  11. 多目标优化算法(一)NSGA-Ⅱ(NSGA2)
  12. 湖南职称计算机模拟试题,湖南职称计算机考试培训软件:集职称计算机考试模拟题、长沙职称计算机考试题库...
  13. SPRING IN ACTION 第4版笔记-第十章Hitting the database with spring and jdbc-002-本章的源代码...
  14. 主板上集成显卡的计算机在进行显示工作,电脑显卡怎么看
  15. Microsoft PowerToys
  16. 链表问题归纳总结--C和C++
  17. android 命名空间的使用
  18. 2021高考辽宁英语成绩查询,2021年辽宁高考英语满分多少分?
  19. 游戏同步方案——帧同步
  20. labelme标签批量转换,labelme_json_to_dataset

热门文章

  1. linux标准I/O——流的打开和关闭
  2. 数据结构与算法——贪心算法
  3. vue data数据修改_VUE的数据响应式
  4. 4-输出基本数据类型
  5. js设计一个带开关的时钟_数电题:三个按键一个灯
  6. mysql 8 修改root密码忘记_忘记mysql8或者mariadb5及以上 的root密码如何更改
  7. c语言字符数组不写,C语言数组
  8. 实现两个点集的欧式距离和cos距离和索引值寻找(含有两种解法,for循环和矩阵操作)
  9. 手写字母数据集转换为.pickle文件
  10. Java8 Stream详解~归约(reduce)