剑指offer之数组中的逆序对

简介: 剑指offer之数组中的逆序对

1 问题

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

比如数列{6,202,100,301,38,8,1},有14个序列对;

比如数列{7, 5, 6, 4},有5个序列对{7,5},{7,6},{7,4},{5,4},{6,4};


2 分析

  我们先了解下归并排序,前面博客有介绍  剑指offer之归并排序 ,我们分析数列{6,202,100,301,38,8,1},

  第一次归并后:{6,202},{100,301},{8,38},{1},这里逆序对1对,就是我们把8插入了38前面,后面只有38一个数据,所以是一度

  第二次归并后:{6,100,202,301},{1,8,38},这里逆序对有3对,我们把100插入了数组{6,202}之间,后面只有202一个元素,所以有一对逆序对,然后1插入了数组{8, 38}最前面,这里后面还有2个元素,所以这有2个逆序对。

  第三次归并后:{1,6,8,38,100,202,301},这里逆序对有10对,把1出入了数组{6,100,202,301}最前面,后面有4个数据,所以4对,然后把8插入数组{6,100,202,301}的第二个数据,后面还有3个数据,就是3对,然后再把38插入数组{6,100,202,301}里面,后面还有3个数据,也就是还有3对逆序对

规律:我们把右边数组里面的元素插入左边数组元素的时候,插进去的位置后面到左边数组尾巴多有多少个元素,就有多少个逆序对,每插入依次,我们统计一次,依次累加。

3 代码实现

#include <stdio.h>
int lastResult = 0;
void merge(int* source, int* temp, int start, int mid, int end)
{
    if (source == NULL || temp == NULL)
    {
        printf("merge source or temp is NULL\n");
        return;
    }
    int i = start, j = mid + 1, k = start;
    int count = 0;
    while (i != mid + 1 && j != end + 1)
    {
        if (source[i] > source[j])
        {
            temp[k++] = source[j++];
            count = mid - i + 1;
            lastResult += count;
        }
        else
            temp[k++] = source[i++];
    }
    while (i != mid + 1)
        temp[k++] = source[i++];
    while (j != end + 1)
        temp[k++] = source[j++];
    for(int h = start; h <= end; ++h)
    {
        source[h] = temp[h];   
    }
    return;
}
int static result = 0;
void mergeSort(int* source, int* temp, int start, int end)
{
    if (source == NULL || temp == NULL)
    {
        printf("mergeSort source or temp is NULL\n");
        return;
    }
    if (start < end)
    {
        int mid = start + (end - start) / 2;
        mergeSort(source, temp, start, mid);
        mergeSort(source, temp, mid + 1, end);
        merge(source, temp, start, mid, end);
    }
}
void printDatas(int* datas, int len)
{
    for (int i = 0; i < len; ++i)
    {
        printf("%d\t", datas[i]);
    }
    printf("\n");
}
int main(void) { 
    int source[] = {7, 5, 6, 4};
    int temp[4];
    int length =  sizeof(source) / sizeof(int);
    mergeSort(source, temp, 0, length - 1);
    printf("lastResult is %d\n", lastResult % 1000000007);
    return 0;
}

4 运行结果

lastResult is 5

这里时间复杂度是O(nlogn),如果我们用暴力求解,时间复杂度就是O(n * n) .

 

相关文章
|
3月前
|
弹性计算 运维 调度
阿里云渠道商:为什么阿里云服务器价格更具竞争力?
阿里云凭借自研技术、规模效应与精细化运营,实现服务器价格优势。全栈创新降低硬件成本,智能调度提升资源利用率,结合弹性计费与长期合约优惠,助力企业降本增效。
|
前端开发
前端base64转Blob,Blob转文件下载
前端将base64字符串转换为Blob对象,再将Blob对象转换为文件并实现下载。包括处理数据URL和纯base64字符串的情况,并提供了一个辅助函数用于转换。
399 2
|
存储 缓存 NoSQL
深入理解Redis数据类型String原理
本文深入探讨了Redis中String数据类型的实现原理和使用场景,基于Redis 5.0版本进行分析。
深入理解Redis数据类型String原理
C++编程练习:设计一个银行账户类,包含户名、帐号以及当前余额属性,并且能完成开户、存款、取款和查询余额等行为。
C++编程练习:设计一个银行账户类,包含户名、帐号以及当前余额属性,并且能完成开户、存款、取款和查询余额等行为。
C++编程练习:设计一个银行账户类,包含户名、帐号以及当前余额属性,并且能完成开户、存款、取款和查询余额等行为。
|
SQL 存储 分布式计算
数仓面试高频考点--解决hive小文件过多问题
小文件产生原因、小文件过多产生的影响以及怎么解决小文件过多问题
1455 0
|
机器学习/深度学习 算法 数据挖掘
第120天:机器学习算法之 K 均值聚类
第120天:机器学习算法之 K 均值聚类
258 0
|
数据安全/隐私保护 C++
C++第12周项目5.2 ——银行系统函数版
课程首页在:http://blog.csdn.net/sxhelijian/article/details/11890759 【项目5-银行系统】  这是我们要做的一个真正的项目!涉及到的技术都用过了,只不过,程序真的要长得多了。  在学习中,总是想要些成就感的。当你没有做过一些事情的时候,总是不能知道所学知识究竟能干些什么。在学习过程中,完成一个像样的项目,那是一件很酷的事情,也让我们更有
1567 0
|
3天前
|
云安全 人工智能 算法
以“AI对抗AI”,阿里云验证码进入2.0时代
三层立体防护,用大模型打赢人机攻防战
1307 3
|
4天前
|
机器学习/深度学习 安全 API
MAI-UI 开源:通用 GUI 智能体基座登顶 SOTA!
MAI-UI是通义实验室推出的全尺寸GUI智能体基座模型,原生集成用户交互、MCP工具调用与端云协同能力。支持跨App操作、模糊语义理解与主动提问澄清,通过大规模在线强化学习实现复杂任务自动化,在出行、办公等高频场景中表现卓越,已登顶ScreenSpot-Pro、MobileWorld等多项SOTA评测。
637 3