7.优化算法之分治-快排归并

news2024/11/25 16:00:28

0.分治

分而治之

1.颜色分类

75. 颜色分类 - 力扣(LeetCode)

给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。

我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。

必须在不使用库内置的 sort 函数的情况下解决这个问题。

示例 1:

输入:nums = [2,0,2,1,1,0]
输出:[0,0,1,1,2,2]

示例 2:

输入:nums = [2,0,1]
输出:[0,1,2]

class Solution {
    public void sortColors(int[] nums) {
        int n=nums.length;
        int left=-1,right=n,i=0;
        while(i<right){//i要扫描完
            if(nums[i]==0){
                swap(nums,++left,i++);
            }else if(nums[i]==2){
                swap(nums,--right,i);
            }else{
                i++;
            }
        }
    }
    public void swap(int[] nums,int x,int y){
        int tmp=nums[x];
        nums[x]=nums[y];
        nums[y]=tmp;
    }
}

2.快速排序

排序数组

给你一个整数数组 nums,请你将该数组升序排列。

class Solution {
    public int[] sortArray(int[] nums) {
        qsort(nums,0,nums.length-1);
        return nums;
    }

    public void qsort(int[] nums,int l,int r){
        if(l>=r){
            return;
        }
        //数组分为三块
        //1.随机在区间内选值
        int key=nums[new Random().nextInt(r-l+1)+l];
        int left=l-1,right=r+1,i=l;
        while(i<right){
            if(nums[i]<key){
                swap(nums,++left,i++);
            }else if(nums[i]==key){
                i++;
            }else{
                swap(nums,--right,i);
            }
        }
        //[l,left],[left+1,right-1],[right,r]
        qsort(nums,l,left);
        qsort(nums,right,r);
    }
    public void swap(int[] nums,int x,int y){
        int tmp=nums[x];
        nums[x]=nums[y];
        nums[y]=tmp;
    }
}

3.数组中的第k个最大元素

215. 数组中的第K个最大元素 - 力扣(LeetCode)

给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。

请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。

示例 1:

输入: [3,2,1,5,6,4], k = 2
输出: 5

示例 2:

输入: [3,2,3,1,2,4,5,5,6], k = 4
输出: 4

class Solution {
    public int findKthLargest(int[] nums, int k) {
        return qsortchoice(nums, 0, nums.length - 1, k);
    }

    public int qsortchoice(int[] nums, int l, int r, int k) {
        while (l == r) {
            return nums[l];
        }
        // 随机在范围内选择对应的数字
        // 随机选择一个基准元素
        int key = nums[new Random().nextInt(r - l + 1) + l];
        // 根据基准元素,使得数组分为三部分
        int left = l - 1, right = r + 1, i = l;
        while (i < right) {
            if (nums[i] < key) {
                swap(nums, ++left, i++);
            } else if (nums[i] == key) {
                i++;
            } else {
                swap(nums, --right, i);
            }
        }
        // 快速选择的算法,分情况讨论
        int b = right - left - 1, c = r - right + 1;
        if (c >= k) {
            return qsortchoice(nums, right, r, k);
        } else if (b + c >= k) {
            return key;
        } else {
            return qsortchoice(nums, l, left, k - b - c);
        }
    }

    public void swap(int[] nums, int x, int y) {
        int tmp = nums[x];
        nums[x] = nums[y];
        nums[y] = tmp;
    }
}

4.最小的K个数

class Solution {
    public int[] inventoryManagement(int[] nums, int k) {
        qsortchoice(nums, 0, nums.length - 1, k);
        int[] ret=new int[k];
        for(int i=0;i<k;i++){
            ret[i]=nums[i];
        }
        return ret;
    }

    public void qsortchoice(int[] nums, int l, int r, int k) {
        while (l == r) {
            return;
        }
        // 随机在范围内选择对应的数字
        // 随机选择一个基准元素
        int key = nums[new Random().nextInt(r - l + 1) + l];
        // 根据基准元素,使得数组分为三部分
        int left = l - 1, right = r + 1, i = l;
        while (i < right) {
            if (nums[i] < key) {
                swap(nums, ++left, i++);
            } else if (nums[i] == key) {
                i++;
            } else {
                swap(nums, --right, i);
            }
        }
        // 快速选择的算法,分情况讨论
        int a=left-l+1,b=right-1-left-1+1;
        if (a>k) {
            qsortchoice(nums, l, left, k);
        } else if (a + b >= k) {
            return;
        } else {
            qsortchoice(nums, right,r, k - a-b);
        }
    }

    public void swap(int[] nums, int x, int y) {
        int tmp = nums[x];
        nums[x] = nums[y];
        nums[y] = tmp;
    }
}

5.归并排序

912. 排序数组 - 力扣(LeetCode)

在递归的时候如果总是需要new一个变量,这是我们可以把这个变量作为全局变量。

class Solution {
    int[] tmp;//定义全局变量,就不用反复new了
    public int[] sortArray(int[] nums) {
        tmp=new int[nums.length];
        mergeSort(nums,0,nums.length-1);
        return nums;
    }

    public void mergeSort(int[] nums,int left,int right){
        if(left>=right){
            return;
        }
        //1.根据中间点划分区间
        int mid=(left+right)/2;
        //[left,mid][mid+1,right]
        //2.先把左右区间排个序 
        mergeSort(nums,left,mid);
        mergeSort(nums,mid+1,right);

        //3.合并两个有序数组
        int cur1=left,cur2=mid+1,i=0;
        while(cur1<=mid&&cur2<=right){
            tmp[i++]=nums[cur1]<=nums[cur2]?nums[cur1++]:nums[cur2++];
        }
        //处理没有遍历完的数组
        while(cur1<=mid){
            tmp[i++]=nums[cur1++];
        }
        while(cur2<=right){
            tmp[i++]=nums[cur2++];
        }
        //还原到nums数组上
        for(int j=left;j<=right;j++){
            nums[j]=tmp[j-left];
        }
    }
}

6.数组中的逆序对

LCR 170. 交易逆序对的总数 - 力扣(LeetCode)

class Solution {
    int[] tmp;
    public int reversePairs(int[] record) {
        int n=record.length;
        tmp=new int[n];
        return mergeSort(record,0,n-1);
    }
    public int mergeSort(int[] nums,int left,int right){
        while(left>=right){
            return 0;
        }
        int ret=0;
        //选择一个中间点,将数组进行划分
        int mid=(left+right)/2;
        //[left,mid][mid+1,right]
        //2.左半部分的个数+右半部分的个数+排序
        ret=ret+mergeSort(nums,left,mid);
        ret=ret+mergeSort(nums,mid+1,right);
        //3.一左一右的个数
        int cur1=left,cur2=mid+1,i=0;
        while(cur1<=mid&&cur2<=right){
            if(nums[cur1]<=nums[cur2]){
                tmp[i++]=nums[cur1++];
            }else{
                ret=ret+mid-cur1+1;
                tmp[i++]=nums[cur2++];
            }
        }
        //4.处理一下后面的排序
        while(cur1<=mid){
            tmp[i++]=nums[cur1++];
        }
        while(cur2<=right){
            tmp[i++]=nums[cur2++];
        }
        for(int j=left;j<=right;j++){
            nums[j]=tmp[j-left];
        }
        return ret;

    }
}

 7.计算右侧⼩于当前元素的个数(难点)

315. 计算右侧小于当前元素的个数 - 力扣(LeetCode)

class Solution {
    int[] ret;
    int[] index; // 标记 nums 中当前元素的原始下标
    int[] tmpIndex;
    int[] tmpNums;

    public List<Integer> countSmaller(int[] nums) {
        int n = nums.length;
        ret = new int[n];
        index = new int[n];
        tmpIndex = new int[n];
        tmpNums = new int[n];
        // 初始化 index 数组
        for (int i = 0; i < n; i++) {
            index[i] = i;
        }
        mergeSort(nums, 0, n - 1);
        List<Integer> l = new ArrayList<Integer>();
        for (int x : ret) {
            l.add(x);
        }
        return l;
    }

    public void mergeSort(int[] nums, int left, int right) {
        if (left >= right) {
            return;
        }
        // 1. 根据中间元素划分区间
        int mid = (left + right) / 2;
        // [left, mid] [mid + 1, right]
        // 2. 处理左右两个区间
        mergeSort(nums, left, mid);
        mergeSort(nums, mid + 1, right);
        // 3. 处理⼀左⼀右的情况
        int cur1 = left, cur2 = mid + 1, i = 0;
        while (cur1 <= mid && cur2 <= right) { // 降序排序
            if (nums[cur1] <= nums[cur2]) {
                tmpNums[i] = nums[cur2];
                tmpIndex[i++] = index[cur2++];
            } else {
                ret[index[cur1]] += right - cur2 + 1; // 重点
                tmpNums[i] = nums[cur1];
                tmpIndex[i++] = index[cur1++];
            }
        }
        // 4. 处理剩余的排序⼯作
        while (cur1 <= mid) {
            tmpNums[i] = nums[cur1];
            tmpIndex[i++] = index[cur1++];
        }
        while (cur2 <= right) {
            tmpNums[i] = nums[cur2];
            tmpIndex[i++] = index[cur2++];
        }
        for (int j = left; j <= right; j++) {
            nums[j] = tmpNums[j - left];
            index[j] = tmpIndex[j - left];
        }
    }
}

 8.翻转对

给定一个数组 nums ,如果 i < j 且 nums[i] > 2*nums[j] 我们就将 (i, j) 称作一个重要翻转对

你需要返回给定数组中的重要翻转对的数量。

示例 1:

输入: [1,3,2,3,1]
输出: 2

示例 2:

输入: [2,4,3,5,1]
输出: 3

注意:

  1. 给定数组的长度不会超过50000
  2. 输入数组中的所有数字都在32位整数的表示范围内。

 

class Solution {
    int[] tmp;

    public int reversePairs(int[] nums) {
        int n = nums.length;
        tmp = new int[n];
        return mergeSort(nums, 0, n - 1);
    }

    public int mergeSort(int[] nums, int left, int right) {
        if (left >= right)
            return 0;
        int ret = 0;
        // 1. 根据中间元素,将区间分成两部分
        int mid = (left + right) / 2;
        // [left, mid] [mid + 1, right]
        // 2. 求出左右两个区间的翻转对
        ret += mergeSort(nums, left, mid);
        ret += mergeSort(nums, mid + 1, right);
        // 3. 处理⼀左⼀右 - 先计算翻转对
        int cur1 = left, cur2 = mid + 1, i = left;
        // 降序版本
        while (cur1 <= mid) {
            while (cur2 <= right && nums[cur2] >= nums[cur1] / 2.0)
                cur2++;
            if (cur2 > right)
                break;
            ret += right - cur2 + 1;
            cur1++;
        }
        // 4. 合并两个有序数组
        cur1 = left;
        cur2 = mid + 1;
        while (cur1 <= mid && cur2 <= right)
            tmp[i++] = nums[cur1] <= nums[cur2] ? nums[cur2++] : nums[cur1++];
        while (cur1 <= mid)
            tmp[i++] = nums[cur1++];
        while (cur2 <= right)
            tmp[i++] = nums[cur2++];
        for (int j = left; j <= right; j++)
            nums[j] = tmp[j];

        return ret;
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

weiyang**3.控制台01

1. 搭建单群组FISCO BCOS联盟链 使用开发部署工具 build_chain.sh脚本在本地搭建一条4 节点的FISCO BCOS链&#xff0c;以Ubuntu 22.04 64bit系统为例操作。 1.1 安装依赖 sudo apt install -y openssl curl 1.2 创建操作目录, 下载安装脚本 ## 创建操作目录 cd ~ &&a…

java基于ssm+jsp 个人交友网站

1前台首页功能模块 个人交友网站&#xff0c;在系统首页可以查看首页、交友信息、线下活动、系统公告、论坛信息、我的、跳转到后台、客服等内容&#xff0c;如图1所示。 图1系统功能界面图 用户注册&#xff0c;在用户注册页面可以填写用户账号、密码、用户姓名、年龄等信息进…

[JS]BOM操作

介绍 BOM(Browser Object Model)是浏览器对象模型 window对象是一个全局对象, 也是JS中的顶级对象通过var定义在全局作用域中的变量和函数都会变成window对象的属性和方法window对象下的属性和方法调用时一般省略window 间歇函数 定时器 定时器是间歇函数的一种, 可以每个每…

java基于ssm+jsp 高校信息资源共享平台

1前台首页功能模块 高校信息资源共享平台&#xff0c;在系统首页可以查看首页、课程信息、教学资源、新闻资讯、我的、跳转到后台等内容&#xff0c;如图1所示。 图1前台首页功能界面图 学生信息登录、学生信息注册&#xff0c;在注册页面可以填写账号、姓名、手机、邮箱、身…

C#基于SkiaSharp实现印章管理(3)

本系列第一篇文章中创建的基本框架限定了印章形状为矩形&#xff0c;但常用的印章有方形、圆形等多种形状&#xff0c;本文调整程序以支持定义并显示矩形、圆角矩形、圆形、椭圆等4种形式的印章背景形状。   定义印章背景形状枚举类型&#xff0c;矩形、圆形、椭圆相关的尺寸…

【人工智能】—葡萄牙酒店预订信息多维度分析|预测是否取消预定算法模型大乱斗

引言 在当今数字化时代&#xff0c;数据驱动的决策在各个行业中变得越来越重要。酒店业&#xff0c;作为旅游和休闲服务的核心部分&#xff0c;正面临前所未有的机遇和挑战。随着在线预订平台的兴起&#xff0c;客户行为数据的积累为酒店提供了洞察消费者需求和优化运营策略的…

存储管理(三):分区表

什么是分区表 假设存在表t&#xff1a; CREATETABLE t (ftimedatetime NOT NULL,c int(11) DEFAULT NULL,KEY (ftime) )ENGINEInnoDB DEFAULT CHARSETlatin1 PARTITION BY RANGE (YEAR(ftime)) (PARTITION p_2017 VALUES LESS THAN (2017) ENGINE InnoDB,PARTITION p_2018 VA…

【Python】已解决:ModuleNotFoundError: No module named ‘sklearn‘

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决&#xff1a;ModuleNotFoundError: No module named ‘sklearn‘ 一、分析问题背景 在进行机器学习项目时&#xff0c;Scikit-Learn&#xff08;简称sklearn&#xff09;是一…

MySQL的limit关键字和聚合函数讲解

目录 一、MySQL数据库介绍二、MySQL聚合函数三、MySQL数据排序分组四、MySQL的limit关键字 一、MySQL数据库介绍 MySQL是一种广泛使用的开源关系型数据库管理系统&#xff0c;由瑞典MySQL AB公司开发&#xff0c;后被Sun Microsystems收购&#xff0c;最终成为Oracle公司的一部…

Consul入门笔记

简介 Consul&#xff0c;HashiCorp公司推出的开源工具&#xff0c;用于实现分布式系统的服务发现与配置。与其他分布式服务注册与发现的方案&#xff0c;Consul的方案更一站式&#xff0c;内置服务注册与发现框架、分布一致性协议实现、健康检查、K/V存储、多数据中心方案&…

地图初始化-多视图几何基础

在ORB-SLAM2中初始化和使用的传感器类型有关&#xff0c;其中单目相机模式初始化相对复杂&#xff0c;需要运行一段时间才能成功初始化。而双目相机、 RGB-D相机模式下比较简单&#xff0c;一般从第一帧开始就可以完成初始化。 为什么不同传感器类型初始化差别这么大呢&#x…

springboot宠物医院管理系统-计算机毕业设计源码07221

目 录 1 绪论 1.1 选题背景和意义 1.2国内外研究现状 1.3论文结构与章节安排 2 宠物医院管理系统系统分析 2.1 可行性分析 2.1.1技术可行性分析 2.1.2 操作可行性分析 2.1.3 法律可行性分析 2.2 系统功能分析 2.2.1 功能性分析 2.2.2 非功能性分析 2.3 系统用例分…

metasfresh开源ERP系统Windows开发环境配置参考

目录 概述 开发环境 配置过程 后端启动 前端启动 登陆系统 其他 概述 Compiere闭源之后衍生出了Admpiere等若干开源的产品&#xff0c;metasfresh就是其中之一&#xff0c;metasfresh截至发稿时在GitHub上已有64000多次的修改提交&#xff0c;而且仍在维护中&#xff0…

vue3-cropperjs图片裁剪工具-用户上传图片截取-(含预览视频)

效果图 上传图片弹窗预览 对于这个上传图片样式可以参考 官方原代码 官网传送入口 Upload 上传 | Element Plus (element-plus.org) <template><el-uploadclass"upload-demo"dragaction"https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6…

使用label-studio对OCR数据进行预标注

导读 label-studio作为一款数据标注工具相信大家都不陌生&#xff0c;对于需要进行web数据标注协同来说应该是必备工具了&#xff0c;标注的数据类型很全涉及AI的各个任务(图像、语音、NLP、视频等)&#xff0c;还支持自定义涉及模版。 然而&#xff0c;我们在标注数据的过程…

【简单讲解下Fine-tuning BERT,什么是Fine-tuning BERT?】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

<Python><ffmpeg>基于python使用PyQt5构建GUI实例:音频格式转换程序(MP3/aac/wma/flac)(优化版2)

前言 本文是基于python语言使用pyqt5来构建的GUI,功能是使用ffmpeg来对音频文件进行格式转换,如mp3、aac、wma、flac等音乐格式。 UI示例: 环境配置 系统:windows 平台:visual studio code 语言:python 库:pyqt5、ffmpeg 概述 本文是建立在之前的博文的基础上的优化版…

Linux多进程和多线程(二)-进程间通信-管道用法

进程间通信 关于多进程的通信管道无名管道(匿名管道)创建无名管道示例:创建子进程,父进程通过管道向子进程发送消息无名管道(匿名管道) 的特点 有名管道(命名管道) 创建有名管道需要调⽤ mkfifo() 函数示例:创建两个没有关联关系的进程,通过有名管道通信 注意: 缺点优点 关于判…

烧结刚玉砂轮片 磨具用晶谷低温陶瓷结合剂玻璃粉

晶谷CBN 砂轮磨具用低温陶瓷结合剂玻璃粉的一些特点如下&#xff1a; - 软化点&#xff1a;通常为450~650度&#xff1b; - 膨胀系数&#xff1a;50~12010-7&#xff1b; - 粒径&#xff1a;300~3000目&#xff08;可按要求订做&#xff09;&#xff1b; - 外观颜色&#xff…

6. 较全的Open3D点云数据处理(python)

注意&#xff1a;以下内容来自博客爆肝5万字❤️Open3D 点云数据处理基础&#xff08;Python版&#xff09;_python 点云 焊缝-CSDN博客&#xff0c;这篇博客写的全且详细&#xff0c;在这里是为了记笔记方便查看&#xff0c;并非抄袭。 1.点云的读写 代码如下&#xff1a; …