leetcode - 分治思想

分治 - 快排

这里快排我们统一使用 数组分三块 和 随机产生基准值的方法实现排序

数组分三块:

. - 力扣(LeetCode)

整个思想即将数组按照基准值分为三个区间 , 具体实现: 三指针实现.  遍历指针 , 左区间右边界指针 , 右区间左边界指针

class Solution {//三指针法//格外注意边界值问题//[0,left - 1]  值为0//[left,right]  值为1//[right + 1,nums,length - 1] 值为2public void sortColors(int[] nums) {int left = 0;int right = nums.length - 1;int i = 0;while(i <= right) {if(nums[i] == 0) swap(left ++,i ++,nums);else if(nums[i] == 1) i ++;else swap(right --,i,nums);//注意这里右边交换时i不用++,}}private void swap(int left,int right,int[] nums) {int cur = nums[left];nums[left] = nums[right];nums[right] = cur;}
}

过程

为什么要使用随机数?   基于随机数产生基准值而进行快排时,时间复杂度最为接近O(Logn)

class Solution {public int[] sortArray(int[] nums) {sort(0 , nums.length - 1 , nums);return nums;}private void sort(int left , int right , int[] nums){//递归结束条件if(left >= right) return;int random = new Random().nextInt(right - left + 1);int flag = nums[random + left];//确定基准值int leftFlag = left;int rightFlag = right;int cur = left;while(cur <= rightFlag){if(nums[cur] == flag) cur ++;else if(nums[cur] > flag) swap(nums , cur , rightFlag --);else swap(nums , cur++ , leftFlag ++);}//循环结束时,leftModel - 1为左区间最后一个元素 , leftModel + 1为右区间最后一个元素//递归sort(left , leftFlag - 1 ,nums);sort(rightFlag + 1 , right , nums);}private void swap(int[] nums , int l1 , int l2) {int cur = nums[l1];nums[l1] = nums[l2];nums[l2] = cur;}}

快速选择算法:

. - 力扣(LeetCode)    数组中第k个最大元素  , 要求时间复杂度O(n). 

这道题比较容易想到的解法是 借助堆.    但是题目中要求时间复杂度为On , 堆就不满足要求了.

时间复杂度为O(n). 我们就要想到快速选择排算法

原理:  快排数组分三段的基础上不去对每一段进行排序,而是通过三个区间的元素数量判断目标元素在哪一个区间进行分类讨论:

class Solution {//快速选择算法//基于快排数组分三块的思想:分三块后通过分类确定目标范围private static int dest;public int findKthLargest(int[] nums, int k) {Solution s = new Solution();s.quickChoose(0 , nums.length - 1 , nums , k);return dest;}private void quickChoose(int left , int right , int[] nums , int k){if(right <= left) {dest = nums[left];//这里不要忘记赋值return;}int flag = nums[new Random().nextInt(right - left + 1) + left];System.out.println(left+":" + right+":" +flag);int l = left;int r = right;int cur = left;while(cur <=  r){if(nums[cur] == flag) cur ++;else if(nums[cur] > flag) swap(nums , r -- , cur);//注意右边换过来的是一个新值,cur不进行++else if(nums[cur] < flag) swap(nums , l ++ , cur ++);}//分类讨论 , 根据区间内元素的数量确定下一步计划//1: 目标元素在大于基准值的区间if(right - r >= k) quickChoose(r + 1 , right ,nums , k);//2: 目标元素等于基准值,直接进行返回else if(right - l + 1 >= k) {dest = flag;return;}//3:目标元素在小于基准值的区间else quickChoose(left , l - 1, nums , k - (right - l + 1));}private void swap(int[] nums , int num1 , int num2) {int cur = nums[num1];nums[num1] = nums[num2];nums[num2] = cur;}}

. - 力扣(LeetCode)   库存管理: 选出库存最小的cnt个商品

class Solution {private int str;private int end;//使用快速选择排序public int[] inventoryManagement(int[] stock, int cnt) {quickSort(stock , 0 , stock.length - 1 , cnt);int[] dest = new int[cnt];for(int i = 0;i < cnt;i ++) {dest[i] = stock[i];}return dest;}private void quickSort(int[] nums , int left , int right , int cnt) {if(left >= right) return;int l = left;int r = right;int cur =  left;int flag = nums[new Random().nextInt(right - left + 1) + left];while(cur <= r){if(nums[cur] == flag) cur ++;else if(nums[cur] > flag) swap(r -- , cur , nums);else swap(l ++ , cur++ , nums);}//分类讨论if(l - left > cnt) quickSort(nums , left , l - 1 , cnt);else if(r - left + 1 >= cnt) return;else quickSort(nums , r + 1, right , cnt - (r - left + 1));}private void swap(int num1 , int num2 , int[] nums) {int temp = nums[num1];nums[num1] = nums[num2];nums[num2] = temp;}
}

分治 - 归并

核心思想:   将一个问题分成若干个规模较小的子问题,分别求解后,再将子问题的结果合并,得到原问题的解。归并排序的核心步骤分为两个部分:“分”和“合”。

归并排序

:. - 力扣(LeetCode)

 public int[] sortArray(int[] nums) {sort(nums , 0 , nums.length - 1);return nums;}private void sort(int[] nums , int left , int right) {if(left >= right) return;//不断递归,将数组分割成俩部分,对两部分别再进行分割,直到每一部只剩下一个元素 , 俩俩进行合并int mid = left + (right - left) / 2;sort(nums , left , mid);sort(nums , mid + 1 , right);sortHelper(nums , left , mid , right);//合并的逻辑}//合并的俩个数组分别已经有序 , 建立一个新数组,设置俩个指针对俩个数组进行比较赋值到新数组上,使新数组比较//不要直接再原数组上进行比较交换 , 会打乱数组的有序性 , 将问题复杂化private void sortHelper(int[] nums , int left , int mid , int right) {int l = left;int r = mid + 1;int[] temp = new int[right - left + 1];int cur = 0;while(l <= mid && r <= right) {while(l <= mid && nums[l] <= nums[r]) temp[cur ++] = nums[l ++];while(r <= right && nums[r] <= nums[l]) temp[cur ++] = nums[r ++];}if(l <= mid){while(l <= mid)temp[cur ++] = nums[l ++];}if(r <= right) {while(r <= right) temp[cur ++] = nums[r ++];}for(int i = 0;i < temp.length;i ++) {nums[left + i] = temp[i];}}

优化 : 在进行合并时创建一个全局的,与原数组等大小的临时数组 , 这样就能避免每次进行合并时创建数组的开销.

例题

统计逆序对:  . - 力扣(LeetCode)

在上述归并的逻辑上加上 数组间统计逆序对 的逻辑即可

class Solution {//在进行数组之间合并排序之前加上一个统计数组间逆序队的逻辑`即可public int reversePairs(int[] record) {return sort(record , 0 , record.length - 1);}private int sort(int[] nums  , int left , int right) {if(left >= right) return 0;int mid = left + (right - left) / 2;int num1 = sort(nums , left , mid);int num2 = sort(nums , mid + 1 , right);int num3 = sortHelper(nums , left , mid , right);return (num1 + num2 + num3);}private int sortHelper(int[] nums ,int left ,int mid , int right){int l = left;int r = mid + 1;int count = 0;int[] model = new int[right - left + 1];int cur = 0;while(l <= mid && r <= right){while(l <= mid && nums[l] <= nums[r]) model[cur ++] = nums[l ++];while(r <= right && nums[r] < nums[l]){count += mid - l + 1;//统计逆序对; 因为合并的俩个数组已经分别有序,所以只需要统计数组间即可model[cur ++] = nums[r ++];}}while(l <= mid) model[cur ++] = nums[l ++];while(r <= right) model[cur ++] = nums[r ++];for(int i = 0;i < model.length;i ++) {nums[left + i] = model[i];}return count;}
}

右侧小于自己的数:. - 力扣(LeetCode)

首先:这道题使用暴力求解一定会超时

这道题进行归并的问题是: 归并排序后会进行元素交换, 交换后元素顺序被打乱  , 我们在进行合并数组时统计出来右侧小于当前元素的数后不知道这个元素的原始下标 .  所以这道题相比于上面求逆序对 , 需要多维护一个存储元素下标的数组.  原数组元素顺序改变时 , 这个存储下标的数组也随之进行改变 , 这样,我们就能通过nums中元素的下标拿到当前元素的初始位置 .

class Solution {private int[] indexMoel;//存储每个元素的原始位置 , 随着nums元素交换而交换,nums元素下标对应到indexModel上就是初始元素的位置,通过初始元素位置在dest上进行数量更新private int[] dest;//存储目标元素private int[] numsTemp;//使用全局数组进行合并,避免每次合并创建临时数组的开销private int[] indexTemp;public List<Integer> countSmaller(int[] nums) {indexMoel = new int[nums.length];numsTemp = new int[nums.length];indexTemp = new int[nums.length];dest = new int[nums.length];for(int i = 0;i < nums.length;i ++) {indexMoel[i] = i;}sort(nums , 0 , nums.length - 1);List<Integer> list = new ArrayList<>();for(int i = 0;i < dest.length;i ++) {list.add(dest[i]);}return list;}private void sort(int[] nums , int left , int right) {if(left >= right) return;int mid = left + (right - left) / 2;sort(nums , left , mid);sort(nums , mid + 1 , right);sortHelper(nums , left , mid , right);}private void sortHelper(int[] nums , int left , int mid , int right) {int l = left;int r = mid + 1;int cur1 = 0;int cur2 = 0;//降序排序 , 更好统计while(l <= mid && r <= right) {if(nums[l] > nums[r]) {dest[indexMoel[l]] += right - r + 1;//通过indexmodel拿到当前元素的初始位置进行统计numsTemp[cur1 ++] = nums[l];indexTemp[cur2 ++] = indexMoel[l ++];//indexModel随着nums的交换而交换}else {numsTemp[cur1 ++] = nums[r];indexTemp[cur2 ++] = indexMoel[r ++];}}while(l <= mid){numsTemp[cur1 ++] = nums[l];indexTemp[cur2 ++] = indexMoel[l ++];}while(r <= right){numsTemp[cur1 ++] = nums[r];indexTemp[cur2 ++] = indexMoel[r ++];}for(int i = 0;i < cur1;i ++) {nums[i + left] = numsTemp[i];indexMoel[i + left] = indexTemp[i]; }}
}

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

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

相关文章

卸载完mathtype后,删除word加载项中的mathtype

请参考博客“卸载完mathtype后&#xff0c;word加载项中还是有mathtype的解决方法_怎么删除word加载项里的mathtype-CSDN博客”以及 “安装卸载MathType经验解决MathType DLL找不到的问题——超实用_mathtype dll cannot-CSDN博客” 如果在删除.dotm文件时&#xff0c;删不掉…

随着访问范围的扩大 OpenAI o1-mini 现已向免费用户开放

上周&#xff0c;OpenAI 展示了其最新的大型语言模型&#xff08;LLM&#xff09;–OpenAI o1及其小兄弟 OpenAI o1-mini。该公司在公告中称&#xff0c;Plus 和 Team 用户可在公告发布之日起访问该模型。企业和教育用户将在本周获得该模型&#xff0c;而免费用户最终将获得 o1…

Golang | Leetcode Golang题解之第404题左叶子之和

题目&#xff1a; 题解&#xff1a; func isLeafNode(node *TreeNode) bool {return node.Left nil && node.Right nil }func sumOfLeftLeaves(root *TreeNode) (ans int) {if root nil {return}q : []*TreeNode{root}for len(q) > 0 {node : q[0]q q[1:]if no…

Mac 上,终端如何开启 proxy

前提 确保你的浏览器可以访问 google&#xff0c;就是得先有这个能力 步骤 查看网络的 http/https 还有 socks5 的 port配置 .zshrc 查看 port 点击 wifi 设置 以我的为例&#xff0c;我的 http/https 都是 7890&#xff0c; socks5 是 7891 查看代理的port 以我的软件…

清华团队发布鼻咽癌诊断模型,自动从HE染色图像生成EBER染色图像|文献精析·24-09-18

小罗碎碎念 今天精读的这篇文章于2024年7月22日发表&#xff0c;作者来自清华大学和广西大学。 角色姓名单位名称&#xff08;中文&#xff09;第一作者曾清华大学珠三角研究院医学光学技术研发中心&#xff0c;广州通讯作者何清华大学深圳国际研究生院生物制药与健康工程研究所…

Ubuntu系统入门指南:常用命令详解

Ubuntu系统入门指南&#xff1a;常用命令详解 引言 Ubuntu是一个基于Linux内核的开源操作系统&#xff0c;由Canonical公司和社区共同开发和维护。它以易用性、稳定性和广泛的软件支持而著称&#xff0c;广泛应用于个人电脑、服务器和云计算环境。对于新手来说&#xff0c;掌…

【Django5】django的helloworld

安装django pip install djangoDjango官方中文文档 https://docs.djangoproject.com/zh-hans/5.1/Github链接 https://github.com/django/django创建Django项目 cd到想要创建项目的文件夹下&#xff0c;输入以下命令创建项目 这行代码将会在当前目录下创建一个 mysite 目录 …

算法.图论-并查集上

文章目录 1. 并查集介绍2. 并查集的实现2.1 实现逻辑2.2 isSameSet方法2.3 union方法(小挂大优化)2.4 find方法(路径压缩优化) 3. 并查集模板 1. 并查集介绍 定义&#xff1a; 并查集是一种树型的数据结构&#xff0c;用于处理一些不相交集合的合并及查询问题&#xff08;即所…

linux 解压缩

1、tar命令 # 压缩文件 file1 和目录 dir2 到 test.tar.gz tar -zcvf test.tar.gz file1 dir2 # 解压 test.tar.gz&#xff08;将 c 换成 x 即可&#xff09; tar -zxvf test.tar.gz # 列出压缩文件的内容 tar -ztvf test.tar.gz 释义&#xff1a;-z : 使用 gzip 来压缩和解压…

JavaDS —— 图

图的概念 图是由顶点集合以及顶点之间的关系组成的一种数据结构&#xff1a;G &#xff08;V&#xff0c;E&#xff09; 其中 V 表示的是顶点集合 &#xff1a; V { x | x 属于某个数据对象集} 是有穷非空集合 E 叫做边的集合 &#xff1a; E {(x, y) | x, y 属于 V} 或者 …

Next.js 14 如何在服务端页面中使用客户端渲染组件

在Next.js中&#xff0c;默认就是使用服务端渲染的&#xff0c;那如何在服务端页面中包含客户端组件呢&#xff0c;以下是试例&#xff1a; 在ArticlePage.js中&#xff1a; import DeleteButton from /components/DeleteBtnexport default async function ArticlePage(){retu…

Qt 模型视图(二):模型类QAbstractItemModel

文章目录 Qt 模型视图(二)&#xff1a;模型类QAbstractItemModel1.基本概念1.1.模型的基本结构1.2.模型索引1.3.行号和列号1.4.父项1.5.项的角色1.6.总结 Qt 模型视图(二)&#xff1a;模型类QAbstractItemModel ​ 模型/视图结构是一种将数据存储和界面展示分离的编程方法。模…

Kotlin cancel CoroutineScope.launch的任务后仍运行

Kotlin cancel CoroutineScope.launch的任务后仍运行 import kotlinx.coroutines.*fun main() {runBlocking {val coroutineScope CoroutineScope(Dispatchers.IO)val job coroutineScope.launch {var i 0while (i < Int.MAX_VALUE) {iprintln(i)}}// 2ms 取消协程delay(…

搜索小车运动最短路径python代码实现

一、实验任务 场地中正方格代表障碍物&#xff0c;选取小车运动起点和终点。编程探究小车从起点运动到终点&#xff0c;总共有几种可行的路径&#xff08;路径不含重叠部分&#xff09;&#xff0c;同时找出最短路径并可视化。 二、实验思路 把场地抽象化为69的平面矩阵&…

五种嵌入式中常见网络协议栈

一.LWIP 1.介绍 LwIP&#xff08;Lightweight IP&#xff09;是一个由瑞典计算机科学院&#xff08;Swedish Institute of Computer Science&#xff09;开发的轻量级TCP/IP协议栈&#xff0c;专为资源有限的嵌入式系统而设计。它以其小巧且功能完善的特性&#xff0c;在物联…

Deep Learning-Based Object Pose Estimation:A Comprehensive Survey

论文&#xff1a;https://arxiv.org/pdf/2405.07801v3 项目&#xff1a;https://github.com/CNJianLiu/Awesome-Object-Pose-Estimation 年份&#xff1a;2024 方向&#xff1a;姿态估计 1. 目标姿态估计定义 估计图像中目标相对于相机的姿态&#xff0c; 目标姿态估计是增…

YoloV8 trick讲解

1.将 YOLOv5 的 C3结构换成了梯度流更丰富的 C2f结构: C3 C3 模块的设计灵感来自 CSPNet&#xff0c;其核心思想是将特征图的部分通道进行分割和并行处理&#xff0c;目的是减少冗余梯度信息&#xff0c;同时保持较高的网络表达能力。C3 结构与传统的残差结构类似&#xff0c;但…

yolov5/8/9/10模型在VOC数据集上的应用【代码+数据集+python环境+GUI系统】

yolov5/8/9/10模型在VOC数据集上的应用【代码数据集python环境GUI系统】 1.背景意义 VOC数据集被广泛应用于计算机视觉领域的研究和实验中&#xff0c;特别是目标检测和图像识别任务。许多知名的目标检测算法都使用VOC数据集进行训练和测试。VOC挑战赛&#xff08;VOC Challeng…

neo4j安装启动教程+对应的jdk配置

参考这位博主的视频教程&#xff1a;neo4j社区windows版下载 一、官网下载neo4j的安装包 &#xff08;1&#xff09;官网下载页面 &#xff08;2&#xff09;上一步 【download】之后&#xff0c;会自动下载&#xff0c;如果没有&#xff0c;点击【here】 这里可以看到一行字…

模型训练时CPU和GPU大幅度波动——可能是数据的读入拖后腿

模型训练时CPU和GPU大幅度波动——可能是数据的加载拖后腿 问题 在进行猫狗大战分类任务时&#xff0c;发现模型训练时CPU和GPU大幅度波动&#xff0c;且模型训练速度很慢。 原因 ​ 初步分析可能是数据加载&#xff08;包括数据的transform&#xff0c;我用了Resize&#…