每日一题《剑指offer》数组篇之数组中的逆序对

简介: 每日一题《剑指offer》数组篇之数组中的逆序对

数组中的逆序对

难度:中等

描述

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

数据范围

对于 50%的数据, size≤104

对于 100%的数据,size≤105

数组中所有数字的值满足 0≤val≤109

举例

image.png

解题思路

因为我们在归并排序过程中会将数组划分成最小为1个元素的子数组,然后依次比较子数组的每个元素的大小,依次取出较小的一个合并成大的子数组。


//取中间
int mid = (left + right) / 2; 
//左右划分合并
merge(divide(left, mid, data, temp), divide(mid + 1, right, data, temp));

这里我们也可以用相同的方法划分,划分之后相邻一个元素的子数组就可以根据大小统计逆序对,而不断往上合并的时候,因为已经排好序了,我们逆序对可以往上累计。我们主要有以下三个阶段。

  • step 1: 划分阶段:将待划分区间从中点划分成两部分,两部分进入递归继续划分,直到子数组长度为1.
  • step 2: 排序阶段:使用归并排序递归地处理子序列,同时统计逆序对,因为在归并排序中,我们会依次比较相邻两组子数组各个元素的大小,并累计遇到的逆序情况。而对排好序的两组,右边大于左边时,它大于了左边的所有子序列,基于这个性质我们可以不用每次加1来统计,减少运算次数。
  • step 3: 合并阶段:将排好序的子序列合并,同时累加逆序对。

实现代码(java)


public class Solution {
    public int mod = 1000000007;
    public int mergeSort(int left, int right, int [] data, int [] temp){
        //停止划分
        if(left >= right)    
            return 0;
        //取中间
        int mid = (left + right) / 2; 
        //左右划分合并
        int res = mergeSort(left, mid, data, temp) + mergeSort(mid + 1, right, data, temp); 
        //防止溢出
        res %= mod;  
        int i = left, j = mid + 1;
        for(int k = left; k <= right; k++)
            temp[k] = data[k];
        for(int k = left; k <= right; k++){
            if(i == mid + 1)
                data[k] = temp[j++];
            else if(j == right + 1 || temp[i] <= temp[j])
                data[k] = temp[i++];
            //左边比右边大,答案增加
            else{ 
                data[k] = temp[j++];
                // 统计逆序对
                res += mid - i + 1; 
            }
        }
        return res % mod;
    }
    public int InversePairs(int [] array) {
        int n = array.length;
        int[] res = new int[n];
        return mergeSort(0, n - 1, array, res);
    }
}



相关文章
|
9月前
|
存储 消息中间件 Java
抖音集团电商流量实时数仓建设实践
本文基于抖音集团电商数据工程师姚遥在Flink Forward Asia 2024的分享,围绕电商流量数据处理展开。内容涵盖业务挑战、电商流量建模架构、流批一体实践、大流量任务调优及总结展望五个部分。通过数据建模与优化,实现效率、质量、成本和稳定性全面提升,数据质量达99%以上,任务性能提升70%。未来将聚焦自动化、低代码化与成本优化,探索更高效的流批一体化方案。
601 12
抖音集团电商流量实时数仓建设实践
|
机器学习/深度学习 传感器 自动驾驶
基于深度学习的图像识别技术及其在自动驾驶中的应用####
本文深入探讨了深度学习驱动下的图像识别技术,特别是在自动驾驶领域的革新应用。不同于传统摘要的概述方式,本节将直接以“深度学习”与“图像识别”的技术融合为起点,简述其在提升自动驾驶系统环境感知能力方面的核心作用,随后快速过渡到自动驾驶的具体应用场景,强调这一技术组合如何成为推动自动驾驶从实验室走向市场的关键力量。 ####
392 24
|
11月前
|
设计模式 Java Go
【再谈设计模式】状态模式~对象行为的状态驱动者
状态模式属于行为型设计模式。它将对象的行为封装在不同的状态类中,使得对象在不同的状态下表现出不同的行为。上下文(Context):这是一个包含状态对象的类,它定义了客户感兴趣的接口,并维护一个具体状态对象的引用。上下文将操作委托给当前的状态对象来处理。抽象状态(State):这是一个抽象类或者接口,它定义了一个特定状态下的行为接口。所有具体的状态类都实现这个接口。具体状态(Concrete State):这些是实现抽象状态接口的类,每个具体状态类实现了与该状态相关的行为。
435 18
|
Java
jdk11的HttpClient
本文介绍了JDK 11中新增的HttpClient功能,并通过示例代码展示了如何使用它来发送HTTP请求,包括GET请求和异步请求的处理。
334 2
jdk11的HttpClient
|
缓存 监控 数据处理
【编程底层原理】从播放音乐的网页中提取mp3音频文件的两种方式及背后的技术思考【短连接和长连接】
本文介绍了两种从网页提取音乐文件的方法:一是通过IE临时缓存获取,二是利用开发者模式捕捉网络流量并下载音频URL。同时探讨了网页播放音乐的技术实现,包括短连接和长连接的区别及其适用场景,以及数据传输中的阻塞概念。
2567 0
|
Java 数据安全/隐私保护
使用java操作word
使用java操作word
279 0
|
机器学习/深度学习 数据可视化 数据挖掘
模拟生成问卷数据
模拟生成问卷数据
980 0
|
域名解析 监控 Linux
排查网络-几个步骤 几款工具
先抛个问题,如果哪天突然发现IDC机房 和 公有云 之间的服务无法访问了(排除服务本身的问题之外,可能是网络不通,也可能是网络变的很慢使得资源无法及时下载,从而导致服务无法访问)。
|
存储 程序员 Shell
【C/C++ 内存管理函数】C语言动态内存管理大揭秘:malloc、calloc、realloc与new的对比与差异
【C/C++ 内存管理函数】C语言动态内存管理大揭秘:malloc、calloc、realloc与new的对比与差异
656 0
|
存储 缓存 前端开发
《Webpack5 核心原理与应用实践》学习笔记-> webpack5持久化缓存
《Webpack5 核心原理与应用实践》学习笔记-> webpack5持久化缓存
535 1

热门文章

最新文章