分治算法——优选算法

分治算法——优选算法

        本章我们要学习的是分治算法,顾名思义就是分而治之,把大问题分为多个相同的子问题进行处理,其中我们熟知的快速排序和归并排序用的就是分治算法,所以我们需要重新回顾一下这两个排序。

一、快速排序(三路划分)

1.算法思想:

        首先从数列中确定一个需要排序的数(记为key),把所有key排到它的正确位置(即排序后它的位置),然后同样的方法,使用递归(分治思想)把小于key的区间与大于key的区间进行排序,直到这个区间不存在或只有一个元素时返回。

        具体方法:从左到右遍历数组,并且我们使用三个变量(left,mid,right)把数组划分为四个区间,分别表示小于key,等于key,未遍历,大于key。而mid位置就是此时遍历到的数,判断这个数与key的关系,然后把它放在对应的区间。再用同样方法将大于key和小于key的区间排序。

        注意:在此快速排序我使用了三路划分的优化方法,和对key取用随机值,这样比普通的快速排序效率要高得多,而且是一种很实用的分治算法。

2.代码实现:

 vector<int> sortArray(vector<int>& nums) { srand((unsigned int)time(NULL)); dfs(0,nums.size()-1,nums); return nums; } void dfs(int n,int m,vector<int>& nums) { if(n>=m) return; int key=nums[n+rand()%(m-n+1)]; int left=n-1,right=m+1,mid=n; while(mid<right) { if(nums[mid]<key) swap(nums[++left],nums[mid++]); else if(nums[mid]==key) mid++; else swap(nums[mid],nums[--right]); } dfs(n,left,nums); dfs(right,m,nums); }

二、归并排序

1.算法思想:

        对于一个乱序的数组,我们可以把一分为二,先让两个小数组有序然后再将它们合并。那么如何让这两个小数组有序呢,同样的可以把它们分别再拆开,变成四个小组,然后继续一直往下拆,直到拆到只有一个元素,那么它必然是有序的,最后进行一一合并,这整个的思路有点像二叉树的后续遍历

2.代码实现:

 vector<int> tmp; vector<int> sortArray(vector<int>& nums) { tmp.reserve(nums.size()); dfs(0,nums.size()-1,nums); return nums; } void dfs(int left,int right,vector<int>& nums) { if(left>=right) return; int mid=(left+right)>>1; dfs(left,mid,nums); dfs(mid+1,right,nums); int p1=left,p2=mid+1; int i=left; while(p1<=mid&&p2<=right) tmp[i++]=nums[p1]<=nums[p2]?nums[p1++]:nums[p2++]; while(p1<=mid) tmp[i++]=nums[p1++]; while(p2<=right) tmp[i++]=nums[p2++]; for(int j=left;j<=right;j++) nums[j]=tmp[j]; }

对于快速排序和归并排序,需要了解更多细节请参考下文:

【排序算法】—— 快速排序_快速排序方法-ZEEKLOG博客

【排序算法】—— 归并排序-ZEEKLOG博客

三、快速选择算法

        当我们看到这个题目的时候,可能脑子里很快想到用堆解决TopK问题,或者是使用排序来解决。 但这是一个面试题,以上两种解决方法都不足以让我们拿到offer。需要注意题目描述是任意顺序返回这k个数,而不是有序返回,那么我们就应该意识到应该还有更优的解决方法。

        对于使用堆和排序,时间复杂度都为O(nlogn),而这个题我们可以用快速选择算法,时间复杂度为O(n),这是由快速排序延伸出的一个算法。同样使用分治思想。

算法思想:

class Solution { public: vector<int> smallestK(vector<int>& arr, int k) { srand((unsigned int)time(NULL)); dfs(0,arr.size()-1,arr,k); return {arr.begin(),arr.begin()+k}; } void dfs(int l,int r,vector<int>& arr,int k) { if(l>r) return; int key=arr[rand()%(r-l+1)+l]; int left=l-1,right=r+1,mid=l; while(mid<right) { if(arr[mid]<key) swap(arr[++left],arr[mid++]); else if(arr[mid]==key) mid++; else swap(arr[mid],arr[--right]); } int a=left-l+1,b=mid-left-1; if(k<a) dfs(l,left,arr,k); else if(k<=a+b) return; else dfs(right,r,arr,k-a-b); } };

四、逆序对问题

        关于这个题,最容易想到的就是暴力方法,双重循环,时间复杂度为O(n^2),毫无疑问是通过不了这个题的,这个题我们可以利用归并排序来完成计数,时间复杂度为O(nlogn)。

算法思想:

class Solution { public: int count=0; vector<int> tmp; int reversePairs(vector<int>& record) { tmp.reserve(record.size()); dfs(0,record.size()-1,record); return count; } void dfs(int left,int right,vector<int>& nums) { if(left>=right) return; int mid=(left+right)>>1; dfs(left,mid,nums); dfs(mid+1,right,nums); int p1=left,p2=mid+1; int i=left; while(p1<=mid&&p2<=right) { if(nums[p1]<=nums[p2]) tmp[i++]=nums[p1++]; else count+=mid-p1+1, tmp[i++]=nums[p2++]; } while(p1<=mid) tmp[i++]=nums[p1++]; while(p2<=right) tmp[i++]=nums[p2++]; for(int i=left;i<=right;i++) nums[i]=tmp[i]; } };
非常感谢您能耐心读完这篇文章。倘若您从中有所收获,还望多多支持呀!

Read more

Flutter for OpenHarmony: Flutter 三方库 google_maps 在鸿蒙应用中嵌入全球地图服务的架构实践(跨平台地图方案库)

Flutter for OpenHarmony: Flutter 三方库 google_maps 在鸿蒙应用中嵌入全球地图服务的架构实践(跨平台地图方案库)

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net 前言 在进行 OpenHarmony 的全球化应用开发时,地图服务是出海项目绕不开的核心组件。对于已经在海外市场成熟运行、深度依赖 Google 地图生态的 Flutter 应用,如何将现有的地图逻辑迁移或适配到鸿蒙平台,是许多出海大企关注的焦点。 虽然鸿蒙在国内市场主要使用高德或百度地图,但在处理“全球一张图”需求时,google_maps 相关的 Flutter 插件及其底层的 Dart 模型定义,依然是定义地理围栏、标记点(Marker)和轨迹绘制的标准参考。本篇将探讨如何在鸿蒙跨平台架构中,平衡 Google 地图的通用逻辑与鸿蒙的原生渲染。 一、跨平台地图适配架构 在鸿蒙适配中,我们通常采用“统一接口层,分平台实现”的策略。 模型转换 适配层 Flutter 业务层 (Dart) 地图抽象层

By Ne0inhk
Flutter 组件 csv2json 适配鸿蒙 HarmonyOS 实战:高性能异构数据转换,构建 CSV 流式解析与全栈式数据映射架构

Flutter 组件 csv2json 适配鸿蒙 HarmonyOS 实战:高性能异构数据转换,构建 CSV 流式解析与全栈式数据映射架构

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 组件 csv2json 适配鸿蒙 HarmonyOS 实战:高性能异构数据转换,构建 CSV 流式解析与全栈式数据映射架构 前言 在鸿蒙(OpenHarmony)生态迈向工业数字化、涉及海量历史报表同步、离线数据采集及跨系统异构数据对齐的背景下,如何实现一种既能处理超大规模文本、又能保障转换极速且具备“非阻塞”特性的数据清洗方案,已成为决定应用数据吞吐能力与内存稳健性的核心因素。在鸿蒙设备这类强调 AOT 极致性能与受限内存足迹的环境下,如果应用依然采用原始的循环分割或同步全量加载 CSV,由于由于数据规模的膨胀,极易由于由于“内存瞬时爆表”导致鸿蒙应用的任务栈卡死。 我们需要一种能够流式处理(Streaming)、支持自动化字段映射(Auto-mapping)且具备零样板代码特性的转换方案。 csv2json 为 Flutter 开发者引入了“数据流变幻”范式。它将结构松散的 CSV 文本精确轰击为高维度的 JSON

By Ne0inhk
EnvPilot:一款基于 Rust 的跨平台环境变量神器,一键搞定 Windows/Linux 环境配置!

EnvPilot:一款基于 Rust 的跨平台环境变量神器,一键搞定 Windows/Linux 环境配置!

文章目录 * 1. 项目介绍🎯 * 1.1. 什么是 EnvPilot? * 1.2. 为什么选择 EnvPilot? * 2. 核心优势:四大痛点全部解决!💪 * ✅ 痛点一:添加不生效?已修复! * ✅ 痛点二:删除删不掉?已修复! * ✅ 痛点三:PATH 清理失效?已修复! * ✅ 痛点四:误操作无法恢复?已解决! * 3. 支持的开发环境🛠️ * 4. 详细使用教程📖 * 4.1. Windows 平台使用教程 * 1️⃣ 下载安装 * 2️⃣ 配置环境变量 * 3️⃣ 清除环境变量 * 4.2. Linux 平台使用教程 * 1️⃣ 从源码编译 * 2️⃣ 配置环境变量 * 3️

By Ne0inhk
Spring Boot 机制三: ApplicationContext 生命周期与事件机制源码解析

Spring Boot 机制三: ApplicationContext 生命周期与事件机制源码解析

博主社群介绍: ① 群内初中生、高中生、本科生、研究生、博士生遍布,可互相学习,交流困惑。 ② 热榜top10的常客也在群里,也有数不清的万粉大佬,可以交流写作技巧,上榜经验,涨粉秘籍。 ③ 群内也有职场精英,大厂大佬,跨国企业主管,可交流技术、面试、找工作的经验。 进群免费赠送写作秘籍一份,助你由写作小白晋升为创作大佬,进群赠送ZEEKLOG评论防封脚本,送真活跃粉丝,助你提升文章热度。 群公告里还有全网大赛约稿汇总/博客提效工具集/ZEEKLOG自动化运营脚本 有兴趣的加文末联系方式,备注自己的ZEEKLOG昵称,拉你进群,互相学习共同进步。 文章目录 * Spring Boot 机制三: ApplicationContext 生命周期与事件机制源码解析 * 目录 * 1. Spring Boot 启动概览 * 2. ApplicationContext 生命周期概览 * 3. BeanFactoryPostProcessor 与 BeanPostProcessor 调用顺序

By Ne0inhk