leetcode 315. 计算右侧小于当前元素的个数(hard)【小林优质解法】

链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

代码:

class Solution {
    int[]counts;    //用来存储结果
    int[]index; //用来绑定数据和原下标
    int[]helpNums;  //用于辅助排序 nums 数组
    int[]helpIndex; //用于辅助排序 index 数组

    public List<Integer> countSmaller(int[] nums) {
        List<Integer> list=new ArrayList<>();
        int length=nums.length;
        counts=new int[length];
        index=new int[length];
        helpNums=new int[length];
        helpIndex=new int[length];

        //初始化 index 数组
        for(int i=0;i<length;i++){
            index[i]=i;
        }

        mergeSort(nums,0,length-1);

        for(int count:counts){
            list.add(count);
        }

        return list;
    }

    //统计 nums 数组中 left ~ right 区间中的逆序对,将统计的数据保存到 counts 中
    public void mergeSort(int[] nums,int left,int right){
        //递归出口
        if(left>=right){
            return;
        }

        //int mid=(right-left)/2+left;    //获取中点
        int mid=(left+right)/2;
        mergeSort(nums,left,mid);   //统计左区间的所有逆序对
        mergeSort(nums,mid+1,right);   //统计右区间的所有逆序对

        //统计左边一个数据,右边一个数据构成的逆序对
        int cur1=left,cur2=mid+1,i=0;
        while(cur1<=mid&&cur2<=right){
            //统计逆序对
            if(nums[cur1]>nums[cur2]){
                counts[index[cur1]]+=right-cur2+1;
                //将 nums 数组和 index 数组同步修改
                helpNums[i]=nums[cur1];
                helpIndex[i++]=index[cur1++];
            }else{
                helpNums[i]=nums[cur2];
                helpIndex[i++]=index[cur2++];
            }
        }

        //处理没有遍历到的数据
        while(cur1<=mid){
            helpNums[i]=nums[cur1];
            helpIndex[i++]=index[cur1++];
        }

        while(cur2<=right){
            helpNums[i]=nums[cur2];
            helpIndex[i++]=index[cur2++];
        }

        //用辅助数组中的数据去代替原数组中的数据
        for(int j=left;j<=right;j++){
            nums[j]=helpNums[j-left];
            index[j]=helpIndex[j-left];
        }
    }
}

题解:

        本题和博主写过的另一题的解法几乎一样,推荐看leetcode LCR 170. 交易逆序对的总数(hard)【小林优质解法】

        首先我们来分析一下题意,题目要求我们统计每个数据右边有多少数据小于当前数据,还是比较好理解的,学过线性代数的同学都知道,对于 5,2 这种左边大于右边的数,我们称之为逆序对,所以题目就是要求我们统计数组中每个数据可以组成的逆序对个数

        这道题很容易想出暴力解法,就是遍历出数组中所有两个数的组合,判断其中有多少逆序对即可,但时间复杂度为 O(n^2),是比较糟糕的,在本题中会超时

        现在博主来介绍如何通过归并排序来解决该题,博主就默认大家是很理解归并排序的,要是不理解一定要先理解了归并排序才能看懂下面的内容,推荐看归并排序(递归)

        题目要求统计逆序对个数,我们可以将数组分为左右两个区间,先统计左区间的逆序对个数 A,再统计右区间的逆序对个数 B,最后统计左区间取一个数据,右区间取一个数据组成的逆序对的个数 C,通过 A+B+C 便能得到数组中所有的逆序对个数,其中,统计左区间的逆序对个数 A 和右区间的逆序对个数 B 与统计整个数组的逆序对相同,所以是递归操作,于是我们的目光就要集中在统计左区间取一个数据,右区间取一个数据组成的逆序对的个数 C 上

        我们统计 C 的个数时是在统计完 A 和 B 之后,根据归并排序的操作,此时已经排序好了左边和右边区间的数据,归并排序按照递减排序,如下图:

        用 cur1 和 cur2 遍历左边和右边的区间,找到其中的逆序对

        (1).nums[ cur1 ] > nums[ cur2 ] ,由于在左右区间数据都是递减的,所以 cur2 后面的数据都小于 cur1 指向的数据,此时我们就得到了以 cur1 指向的数据为首的一批逆序对,个数为 right - cur2 + 1 ,要将 nums[ cur1 ] 这个数据的逆序对个数添加到 counts 数组中

        现在就有一个问题,counts 数组对应的是 nums[ cur1 ] 这个数据的原下标,因为数据经过了归并排序,顺序已经打乱了,cur1 不是该数据的原下标,我们如何知道 nums[ cur1 ] 这个数据的原下标呢?这里就需要一个小技巧,我们可以在一开始的时候就创建一个数组 index ,index 数组记录了 nums 数组中每个数据的原下标,如下所示:

nums:5        2        6        1

index:0        1        2        3

        在这之后,nums 数组如何改变。index 数组就如何改变,这样处理后无论数组中的数据如何改变,我们都能知道每个数据对应的原下标是多少,所以得到 nums[ cur1 ] 这个数据的一批逆序对数目后,要执行 counts[ index[ cur1 ] ] + = right - cur2 + 1 ,在本次递归中 nums[ cur1 ] 这个数据的逆序对就获取完了,让 cur1++ 

        刚好对应归并排序,由于要按照递减排序,所以 nums[ cur1 ] > nums[ cur2 ] ,就将 cur1 指向的数据放到辅助数组 helpNums 中,此时 index 数组中的数据也要对应发生改变,放到辅助数组 helpIndex 中,再让 cur1 ++,

        (2).nums[ cur1 ] <= nums[ cur2 ] ,根据递减排序的单调性,因为 cur1 指针右边的数据都小于 cur2 指针指向的数据,所以没有数据能和 nums[ cur2 ] ,构成逆序对,让 cur2 ++,

        刚好对应归并排序,由于要按照递减排序,所以 nums[ cur1 ] 《= nums[ cur2 ] ,就将 cur2 指向的数据放到辅助数组 helpNums 中,此时 index 数组中的数据也要对应发生改变,放到辅助数组 helpIndex 中,再让 cur2 ++,

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/280552.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

学习动态规划不同路径、最小路径和、打家劫舍、打家劫舍iii

学习动态规划|不同路径、最小路径和、打家劫舍、打家劫舍iii 62 不同路径 动态规划&#xff0c;dp[i][j]表示从左上角到(i,j)的路径数量dp[i][j] dp[i-1][j] dp[i][j-1] import java.util.Arrays;/*** 路径数量* 动态规划&#xff0c;dp[i][j]表示从左上角到(i,j)的路径数量…

KG+LLM(一)KnowGPT: Black-Box Knowledge Injection for Large Language Models

论文链接&#xff1a;2023.12-https://arxiv.org/pdf/2312.06185.pdf 1.Background & Motivation 目前生成式的语言模型&#xff0c;如ChatGPT等在通用领域获得了巨大的成功&#xff0c;但在专业领域&#xff0c;由于缺乏相关事实性知识&#xff0c;LLM往往会产生不准确的…

List常见方法和遍历操作

List集合的特点 有序&#xff1a; 存和取的元素顺序一致有索引&#xff1a;可以通过索引操作元素可重复&#xff1a;存储的元素可以重复 List集合的特有方法 Collection的方法List都继承了List集合因为有索引&#xff0c;所以有了很多操作索引的方法 ublic static void main…

sklearn学习的一个例子用pycharm jupyter

环境 运行在jupyter 进行开发。即一个WEB端的开发工具。能适时显示开发的输出。后缀用的是ipynb.pycharm也可以支持。但也要提示按装jupyter. 或直接用andcoda 这里我们用pycharm进行项目创建 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple jupyterlab pip ins…

Java关键字(1)

Java中的关键字是指被编程语言保留用于特定用途的单词。这些关键字不能用作变量名或标识符。以下是Java中的一些关键字&#xff1a; public&#xff1a;表示公共的&#xff0c;可以被任何类访问。 private&#xff1a;表示私有的&#xff0c;只能被定义该关键字的类访问。 cl…

centos 7.9 升级系统默认的python2.7到python 2.7.18

centos 7.9 升级系统默认的python2.7到python 2.7.18 备份旧版本 mv /usr/bin/python /usr/bin/python_2.7.5 下载新版本 Download Python | Python.org Python Release Python 2.7.18 | Python.org wget https://www.python.org/ftp/python/2.7.18/Python-2.7.18.tgz cd /…

2023 IoTDB Summit:天谋科技 CTO 乔嘉林《IoTDB 企业版 V1.3: 时序数据管理一站式解决方案》...

12 月 3 日&#xff0c;2023 IoTDB 用户大会在北京成功举行&#xff0c;收获强烈反响。本次峰会汇集了超 20 位大咖嘉宾带来工业互联网行业、技术、应用方向的精彩议题&#xff0c;多位学术泰斗、企业代表、开发者&#xff0c;深度分享了工业物联网时序数据库 IoTDB 的技术创新…

Rust开发⼲货集(1)--迭代器与消费器

本内容是对 Rust开发干货集[1] 的实践与扩展. iter() 不转移所有权 先简单解释下什么叫"转移所有权": 在 Rust 中&#xff0c;"转移所有权"&#xff08;Ownership Transfer&#xff09;是一种核心概念&#xff0c;它涉及变量和数据的所有权从一个实体转移…

2023.12.28 关于 Redis 数据类型 List 内部编码、应用场景

目录 List 编码方式 早期版本 现今版本 List 实际应用 多表之间的关联关系 消息队列 频道&#xff08;多列表&#xff09;消息队列 微博 Timeline 栈 & 队列 List 编码方式 早期版本 早期版本 List 类型的内部编码方式有两种 ziplist&#xff08;压缩列表&#xf…

vscode: make sure you configure your user.name and user.email in git

一、问题描述 使用VScode编辑代码后&#xff0c;Push到云端报错&#xff1a;Make sure you configure your "user.name" and "user.email" in git 二、解决方案 解决步骤&#xff1a; 1.打开Git Bash&#xff1a; 2.输入命令&#xff1a; git config -…

ElasticSearch学习笔记(二)

通过前面的一阵胡乱操作&#xff0c;显然提升了我的学习兴趣&#xff0c;趁热打铁&#xff0c;接着往下学。还是先看看别人的教程吧。这里我看的是B站上【尚硅谷】的ElasticSearch教程&#xff0c;有兴趣的同学也可以去看看。 一、缘起–索引操作 看B站上的视频教程&#xff0…

命令模式-实例使用

未使用命令模式的UML 使用命令模式后的UML public abstract class Command {public abstract void execute(); }public class Invoker {private Command command;/*** 为功能键注入命令* param command*/public void setCommand(Command command) {this.command command;}/***…

数据库原理与应用快速复习(期末急救)

文章目录 第一章数据库系统概述数据、数据库、数据库管理系统、数据定义、数据组织、存储和管理、数据操纵功能、数据库系统的构成数据管理功能、数据库管理的3个阶段以及特点数据库的特点、共享、独立、DBMS数据控制功能数据库的特点 数据模型两类数据模型、逻辑模型主要包括什…

SVN下载安装(服务器与客户端)

1.下载 服务器下载&#xff1a;Download | VisualSVN Server 客户端下载&#xff1a;自行查找 2. 服务器安装 双击执行 运行 下一步 同意下一步 下一步 选中安装目录 3. 客户端安装 双击执行 下一步 4. 服务器创建仓库 5. 服务器创建用户 6. 客户端获取资源 文件夹右键

基于ssm的便民自行车管理系统的开发与实现+vue论文

摘 要 进入21世纪网络和计算机得到了飞速发展&#xff0c;并和生活进行了紧密的结合。目前&#xff0c;网络的运行速度以达到了千兆&#xff0c;覆盖范围更是深入到生活中的角角落落。这就促使管理系统的发展。管理系统可以实现远程处理事务&#xff0c;远程提交工作和随时追踪…

电路分析基础速成课笔记

基础知识 串并联&#xff0c;短路和断路 电源 例题&#xff1a; 电阻电路的等效变换 电压源串联 u u 1 u 2 uu_1u_2 uu1​u2​ 方向相同直接加&#xff0c;不同取决于大的方向 电流源并联 i i s 1 i s 2 ii_{s_1}i_{s_2} iis1​​is2​​ 电压源和电流源串联 省略电压…

通信原理课设(gec6818) 007:语音识别

目录 1、去科大讯飞官网下载对应的sdk 2、科大讯飞文件夹的意思 3、配置ARM的录音环境 4、编程实现语音识别 我们的需求是将一个语音文件从客户端传到服务器&#xff0c;因此我们最好是选用tcp 现在市面上面常用的语音识别解决方案为&#xff1a;科大讯飞c和百度c 离…

python+django高校教材共享管理系统PyCharm 项目

本中原工学院教材共享平台采用的数据库是mysql&#xff0c;使用nodejs技术开发。在设计过程中&#xff0c;充分保证了系统代码的良好可读性、实用性、易扩展性、通用性、便于后期维护、操作方便以及页面简洁等特点。系统所要实现的功能分析&#xff0c;对于现在网络方便的管理&…

[计算机提升] Windows系统软件:管理类

3.6 系统软件&#xff1a;管理类 3.6.1 运行 通过运行程序&#xff0c;在打开输入框中输入名称&#xff0c;按下回车后可以打开相应的程序、文件夹、文档或Internet资源&#xff1a; 3.6.2 命令提示符&#xff1a;cmd 在Windows系统中&#xff0c;cmd是指"命令提示符…

HTML5+CSS3+JS小实例:过年3D烟花秀

实例:过年3D烟花秀 技术栈:HTML+CSS+JS 效果: 源码: 【HTML】 <!DOCTYPE html> <html lang="zh-CN"> <head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><…