题目描述
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
输入描述:
题目保证输入的数组中没有的相同的数字
数据范围:
对于%50的数据,size<=10^4
对于%75的数据,size<=10^5
对于%100的数据,size<=2*10^5

分析
暴力法,时间O(n2)O(n^2)O(n2)

public class Solution {public int InversePairs(int [] array) {int cnt = 0;for(int i = array.length-1; i >= 0; i--){for(int j = 0; j<i; j++){if (array[j] > array[i]){cnt++;}}}return cnt % 1000000007;}
}

暴力只能通过50%的测试用例,需要改进。

归并排序将数组分为不可再分的单个元素,对两个单个的元素统计其逆序对数量,归并为2个元素,继续两两归并,对归并过程中不同的子数组大小分别统计其逆序对个数。问题是怎么借用这种过程统计数组中出现的逆序对呢?

本解法利用归并排序的过程来统计逆序对个数,本质上和剑指offer上的思路一致。

本解法和剑指offer解法的不同在于:

  1. 数组采用从大到小排序
  2. 设置全局变量统计逆序对个数

拿剑指offer中的例子来说,有4个元素的数组【7,5,6,4】,其逆序对有【7,6】,【7,5】,【7,4】,【6,4】,【5,4】共5个归并排序操作将其分为单个元素7,5,6,4,见图,然后7,5归并时出现一个逆序对【7,5】,归并考虑【7,5】和【6】又出现一个逆序对【7,6】,归并后为【7,6,5】考虑和【4】出现了三个逆序对【7,4】,【6,4】,【5,4】,故一共有5个逆序对。

关键是怎样在归并的时候统计出现的逆序对个数!我设置了一个全局变量,在归并排序的同时统计出现的逆序对,在a[i] > b[j]时,统计从j开始剩余元素的个数,即为a[i]对应的逆序对的个数,这种方法简洁明了,只对归并排序代码做了很少改动。

时间O(nlogn),空间O(n)

cnt = 0
class Solution:def InversePairs(self, data):self.merge_sort(data)return cnt % 1000000007def merge_sort(self, lists):if len(lists) <= 1:return listsmiddle = len(lists)//2left = self.merge_sort(lists[:middle])right = self.merge_sort(lists[middle:])merged = self.merge(left, right)return mergeddef merge(self, a, b):#归并操作,合并两个子数组,注意是从大到小排序global cntc = []i = j = 0while i < len(a) and j < len(b):if a[i] > b[j]:c.append(a[i])i += 1#关键代码,假设左边i=0,j=0,左边最大值比右边最大值大,则#逆序对有len(b)-0个,然后i=1,若还比右边最大值大,则还有#逆序对len(b)-0个,如果比右边值小,则j+1往前一步,就没有逆序对了#本方法对剑指offer改进为按从大到小排序,比较子数组中元素,统计逆序对更加方便cnt += len(b) - jelse:c.append(b[j])j += 1c += a[i:]c += b[j:]return cif __name__ == '__main__':a = [7,5,6,4]s = Solution().InversePairs(a)print(s)#5

由于python语言速度比较慢,程序超时。

Java版程序完美AC,注意排序是按从小到大的顺序

import java.io.IOException;public class Solution {public int cnt = 0;public int InversePairs(int [] array) {if(array != null){merge_sort(array, 0, array.length-1);}return cnt;}public void merge_sort(int [] array, int left, int right){if(left >= right){return ;}int middle = (left + right) / 2;merge_sort(array, left, middle);merge_sort(array, middle+1, right);merge(array, left, middle, right);}public void merge(int []a, int left, int middle, int right){int []tmp = new int[right - left +1];int i = left, j = middle+1, k = 0;while(i <= middle && j <= right){if(a[i] > a[j]){//从小到大排序tmp[k++] = a[j++];//计算子数组中逆序对个数,cnt += middle - i + 1;}else{tmp[k++] = a[i++];}//cnt过大,需要取余数if(cnt >= 1000000007){cnt %= 1000000007;}}//处理剩余的数组元素while(i <= middle){tmp[k++] = a[i++];}while(j <= right){tmp[k++] = a[j++];}//暂存的子数组值复制到原数组for(int p = 0; p < k; p++){a[left + p] = tmp[p];}}
/*public static void main(String[] args)throws IOException {int tmp[] = new int[]{1,2,3,4,5,6,7,0};Solution s = new Solution();int ret = s.InversePairs(tmp);System.out.println(ret);}
*/
}

也可以采用由大到小排序,就是本文的思路了

    public void merge_sort(int [] array, int left, int right){if(left >= right){return ;}int middle = (left + right) / 2;merge_sort(array, left, middle);merge_sort(array, middle+1, right);merge(array, left, middle, right);}public void merge(int []a, int left, int middle, int right){int []tmp = new int[right - left +1];int i = left, j = middle+1, k = 0;while(i <= middle && j <= right){if(a[i] > a[j]){//从大到小排序tmp[k++] = a[i++];//计算子数组中逆序对个数,cnt += right - j + 1;}else{tmp[k++] = a[j++];}//cnt过大,需要余数if(cnt >= 1000000007){cnt %= 1000000007;}}//处理剩余的数组元素while(i <= middle){tmp[k++] = a[i++];}while(j <= right){tmp[k++] = a[j++];}//暂存的子数组值复制到原数组for(int p = 0; p < k; p++){a[left + p] = tmp[p];}}

输入一个数组,求出这个数组中的逆序对的总数相关推荐

  1. 用户输入一个整数,求出它的各个位数,并求各位数之和

    import java.util.Scanner; //用户输入一个整数,求出它的各个位数,并求各位数之和 public class splitInteger { public static void ...

  2. python输入一个正整数n求下列算式的值_C语言编写程序:输入一个正整数x和一个正整数n,求下列算式的值。,C语言 编写一个程序,输入一个正整数,求出它是几位数。...

    导航:网站首页 > C语言编写程序:输入一个正整数x和一个正整数n,求下列算式的值.,C语言 编写一个程序,输入一个正整数,求出它是几位数. C语言编写程序:输入一个正整数x和一个正整数n,求下 ...

  3. 输入一个字符串求出其中逆序数对

    例如:输入daabec,输出5. 即: #include<iostream> #include<cstring> using namespace std; int main() ...

  4. C++求数组中的逆序对

    C++求数组中的逆序对. 如果在数组中的两个数字如果前面的一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数 #include<iostream> ...

  5. c语言数组求逆序对,LeetCode 面试题51. 数组中的逆序对

    面试题51. 数组中的逆序对 题目来源:https://leetcode-cn.com/problems/shu-zu-zhong-de-ni-xu-dui-lcof/ 题目 在数组中的两个数字,如果 ...

  6. 剑指Offer - 面试题51. 数组中的逆序对(归并排序,求逆序对)

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

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

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

  8. 牛客(35)数组中的逆序对

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

  9. 《剑指offer》-- 数组中的逆序对、最小的K个数、从1到n整数中1出现的次数、正则表达式匹配、数值的整数次方

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

最新文章

  1. Android7.1选择时区由默认的GMT+00:00改为GMT+08:00中国标准时间
  2. leetcode733. 图像渲染(bfs)
  3. fastjson反序列化漏洞_【安全风险通告】fastjson反序列化远程代码执行漏洞安全风险通告...
  4. 快应用不会取代 App,未来将赋能 IoT!
  5. 阶段3 1.Mybatis_03.自定义Mybatis框架_6.自定义Mybatis的编码-实现基于XML的查询所有操作...
  6. DS_Store文件泄漏
  7. 扇贝编程python骗局-原来用Python薅羊毛这么简单!后悔错过了那么多机会
  8. VB2010网络通信服务器
  9. 未检测到与wia兼容的设备_关于检测到不兼容硬件设备的解决办法
  10. matlab zmax 光学仿真,基于ZEMAX的光栅干涉仪仿真
  11. c语言数独思路介绍,【数独运算器】,关于数独的解题思路,已经改进。
  12. 重力传感器、加速度传感器以及陀螺仪的区别
  13. matlab cdfx,求助大神
  14. 功能中进行频繁查询、提高查询效率的方法
  15. Emotiv EPOCFLEX 32导脑电仪数据准确导入EEGLAB
  16. HTML,css和JavaScript的基础学习—JavaScript篇
  17. _ctl0_ContentPlaceHolder1 或者 ctl00_ContentPlaceHolder1
  18. scrapy 项目实战(一)----爬取雅昌艺术网数据
  19. 6. ESP8266固件的下载
  20. 罗列当前文件夹下所有文件

热门文章

  1. erlang OTP 通用服务器行为模式理解
  2. 应还金额和最低还款额有什么区别?
  3. 腾讯音乐Q2财报前瞻:这次将会带来哪些惊喜?
  4. 【python刷题笔记01】eval 、 {:.2f}
  5. 【未解决】Arachni 安装遇到问题
  6. openwrt LAN 和 WAN 对调了的处理
  7. 网络前端第六次培训笔记(js)
  8. pwnable.kr之passcode
  9. CAPWAP基础原理
  10. 【架构师之路 二】需要掌握的技能点---工程架构能力