算法思想总结:分治思想

一、颜色划分

. - 力扣(LeetCode)

class Solution {
public:void sortColors(vector<int>& nums) {//三路划分的思想int n=nums.size();int left=-1, right=n,cur=0;while(cur<right){if(nums[cur]==0) swap(nums[++left],nums[cur++]);else if(nums[cur]==1) ++cur;else swap(nums[--right],nums[cur]);}  }
};

二、快排优化(三路划分+随机key)

. - 力扣(LeetCode)

class Solution {
public:vector<int> sortArray(vector<int>& nums) {//三路划分+随机取keysrand((unsigned int)time(NULL));//时间种子qsort(nums,0,nums.size()-1);return nums;}void qsort(vector<int>& nums,int begin,int end){if(begin>=end) return;int key=nums[rand()%(end-begin+1)+begin];int left=begin-1,right=end+1,cur=begin;while(cur<right){if(nums[cur]<key) swap(nums[++left],nums[cur++]);else if(nums[cur]==key) ++cur;else  swap(nums[--right],nums[cur]);}qsort(nums,begin,left);qsort(nums,right,end);}
};

三、数组中的第k个最大元素(快速选择算法)

. - 力扣(LeetCode)

class Solution {
public:int findKthLargest(vector<int>& nums, int k) {//第k大  堆排//第k小//前k大  //快速选择算法//前k小//三路划分 srand(time(NULL));//时间种子return qsort(nums,0,nums.size()-1,k);}int qsort(vector<int>& nums,int begin,int end,int k){if(begin>=end) return nums[begin];//1随机选择基准元素int key=nums[rand()%(end-begin+1)+begin];//2根据基准元素将数组分三块int left=begin-1,right=end+1,cur=begin;while(cur<right){if(nums[cur]<key) swap(nums[++left],nums[cur++]);else if(nums[cur]==key) ++cur;else  swap(nums[--right],nums[cur]);}//3.开始分情况讨论int c=end-right+1;int b=right-1-(left+1)+1;if(c>=k) return qsort(nums,right,end,k);else if(b+c>=k) return key;else return qsort(nums,begin,left,k-b-c);}
};

四、库存管理(Top-k)

. - 力扣(LeetCode)

  

class Solution {
public://最小的k个数vector<int> inventoryManagement(vector<int>& nums, int k){srand(time(NULL));//时间种子qsort(nums,0,nums.size()-1,k);return {nums.begin(),nums.begin()+k};}void qsort(vector<int>& nums,int begin,int end,int k){if(begin>=end) return;int key=nums[rand()%(end-begin+1)+begin];int left=begin-1,right=end+1,cur=begin;while(cur<right){if(nums[cur]<key) swap(nums[++left],nums[cur++]);else if(nums[cur]==key) ++cur;else  swap(nums[--right],nums[cur]);}int a=left+1,b=right-left+1;if(a>k) qsort(nums,begin,left,k);else if(a+b>=k) return;else qsort(nums,right,end,k-a-b); }
};

五、归并排序

. - 力扣(LeetCode)

class Solution {
public://需要一个辅助数组vector<int> temp;//辅助数组vector<int> sortArray(vector<int>& nums) {int n=nums.size();temp.resize(n);MergeSort(nums,0,n-1);return nums;}void MergeSort(vector<int>& nums,int left,int right){if(left>=right) return;//1、找到中间位置int mid=(left+right)>>1;//2 排好左区间,排好右区间MergeSort(nums,left,mid);MergeSort(nums,mid+1,right);//3.进行归并int i=left;//帮助还原int cur1=left,cur2=mid+1;while(cur1<=mid&&cur2<=right) temp[i++]=nums[cur1]<nums[cur2]?nums[cur1++]:nums[cur2++];//4、处理没有归并的区间while(cur1<=mid)   temp[i++]=nums[cur1++];while(cur2<=right) temp[i++]=nums[cur2++];//5、还原for(int j=left;j<=right;++j) nums[j]=temp[j];}
};

六、交易逆序对的总数

. - 力扣(LeetCode)

升序版本:

class Solution {
public:vector<int> temp;//标记数组//1、升序,有多少个数比当前位置大int reversePairs(vector<int>& nums) {int n=nums.size();temp.resize(n);return MergeSort(nums,0,n-1);}int MergeSort(vector<int>& nums,int left,int right){if(left>=right) return 0;int mid=(right+left)>>1;int ret=0;ret+=MergeSort(nums,left,mid);ret+=MergeSort(nums,mid+1,right);//开始进行归并int cur1=left,cur2=mid+1,i=0;while(cur1<=mid&&cur2<=right){if(nums[cur1]<=nums[cur2]) temp[i++]=nums[cur1++];else {ret+=mid-cur1+1;temp[i++]=nums[cur2++];}}while(cur1<=mid) temp[i++]=nums[cur1++];while(cur2<=right) temp[i++]=nums[cur2++];//开始还原for(int j=left;j<=right;++j) nums[j]=temp[j-left];return ret;}
};

降序版本:

class Solution {
public:vector<int> temp;//标记数组//1、升序,前面有多少个数比当前位置大//2、降序,后面有多少数比我当前位置小int reversePairs(vector<int>& nums) {int n=nums.size();temp.resize(n);return MergeSort(nums,0,n-1);}int MergeSort(vector<int>& nums,int left,int right){if(left>=right) return 0;int mid=(right+left)>>1;int ret=0;ret+=MergeSort(nums,left,mid);ret+=MergeSort(nums,mid+1,right);//开始进行归并int cur1=left,cur2=mid+1,i=0;while(cur1<=mid&&cur2<=right){if(nums[cur1]<=nums[cur2]) temp[i++]=nums[cur2++];else {ret+=right-cur2+1;//说明我cur1后面的位置都比你大temp[i++]=nums[cur1++];}}while(cur1<=mid) temp[i++]=nums[cur1++];while(cur2<=right) temp[i++]=nums[cur2++];//开始还原for(int j=left;j<=right;++j) nums[j]=temp[j-left];return ret;}
};

七、计算右侧小于当前元素的个数

. - 力扣(LeetCode)

class Solution {
public:vector<int> ret;//记录返回的结果vector<int> index;//建立一个下标数组和nums数据绑定vector<int> numstemp;vector<int> indextemp;vector<int> countSmaller(vector<int>& nums) {int n=nums.size();ret.resize(n);index.resize(n);numstemp.resize(n);indextemp.resize(n);//初始化index数组for(int i=0;i<n;++i) index[i]=i;//存当前位置对应的下标Mersort(nums,0,n-1);return ret;}void Mersort(vector<int>& nums,int left,int right){if(left>=right) return;int mid=(left+right)>>1;Mersort(nums,left,mid);Mersort(nums,mid+1,right);//开始归并  升序,有多少个数比我当前的位置小int cur1=left,cur2=mid+1,i=left;while(cur1<=mid&&cur2<=right){if(nums[cur1]>nums[cur2]){ret[index[cur1]]+=right-cur2+1;numstemp[i]=nums[cur1];indextemp[i++]=index[cur1++];}else{numstemp[i]=nums[cur2];indextemp[i++]=index[cur2++];}}//填没有进去的区间while(cur1<=mid) {numstemp[i]=nums[cur1];indextemp[i++]=index[cur1++];}while(cur2<=right){numstemp[i]=nums[cur2];indextemp[i++]=index[cur2++];}//还原for(int j=left;j<=right;++j){nums[j]=numstemp[j];index[j]= indextemp[j];}}
};

八、翻转对

. - 力扣(LeetCode)

升序版本:前面有多少元素的一半比我大(升序) 固定cur2  找cur1

class Solution {
public:vector<int> temp;//标记数组//1、升序,前面有多少个数比当前位置大//2、降序,后面有多少数比我当前位置小int reversePairs(vector<int>& nums) {int n=nums.size();temp.resize(n);return MergeSort(nums,0,n-1);}int MergeSort(vector<int>& nums,int left,int right){if(left>=right) return 0;int mid=(right+left)>>1;int ret=0;ret+=MergeSort(nums,left,mid);ret+=MergeSort(nums,mid+1,right);//归并之前先统计翻转对int cur1=left,cur2=mid+1;//升序  锁定cur2,然后统计cur1的一半是否大于cur2while(cur2<=right){while(cur1<=mid&&nums[cur2]>=nums[cur1]/2.0) ++cur1;//此时cur2的位置和cur2后面的位置都符合条件ret+=mid-cur1+1;++cur2;}//开始进行归并cur1=left,cur2=mid+1;//恢复cur1和cur2为初始位置int i=left;while(cur1<=mid&&cur2<=right)temp[i++]=nums[cur1]<nums[cur2]?nums[cur1++]:nums[cur2++];//降序while(cur1<=mid) temp[i++]=nums[cur1++];while(cur2<=right) temp[i++]=nums[cur2++];//开始还原for(int j=left;j<=right;++j) nums[j]=temp[j];return ret;}
};

降序版本:后面有多少元素的两倍比我小(降序) 固定cur1  找cur2

class Solution {
public:vector<int> temp;//标记数组//1、升序,前面有多少个数比当前位置大//2、降序,后面有多少数比我当前位置小int reversePairs(vector<int>& nums) {int n=nums.size();temp.resize(n);return MergeSort(nums,0,n-1);}int MergeSort(vector<int>& nums,int left,int right){if(left>=right) return 0;int mid=(right+left)>>1;int ret=0;ret+=MergeSort(nums,left,mid);ret+=MergeSort(nums,mid+1,right);//归并之前先统计翻转对int cur1=left,cur2=mid+1;//降序  锁定cur1,然后统计cur2位置的2倍是否小于cur1while(cur1<=mid){while(cur2<=right&&nums[cur2]>=nums[cur1]/2.0) ++cur2;//此时cur2的位置和cur2后面的位置都符合条件ret+=right-cur2+1;++cur1;}//开始进行归并cur1=left,cur2=mid+1;//恢复cur1和cur2为初始位置int i=0;while(cur1<=mid&&cur2<=right)temp[i++]=nums[cur1]>nums[cur2]?nums[cur1++]:nums[cur2++];//降序while(cur1<=mid) temp[i++]=nums[cur1++];while(cur2<=right) temp[i++]=nums[cur2++];//开始还原for(int j=left;j<=right;++j) nums[j]=temp[j-left];return ret;}
};

九、区间和的个数

. - 力扣(LeetCode)

class Solution {
public:vector<long> dp;vector<long> temp;int lower, upper;int countRangeSum(vector<int>& nums, int _lower, int _upper){//设置一个前缀和数组dp 则问题等价于求所有下标为(i,j)满足dp[j]-dp[i]属于lower和upper区间//此时是有左右两段的,左右两段是分别有序的,对前缀和数组排序并不会修改数组中元素的值,只是改变了元素位置,如对leftright=35位置的前缀和排序,排序后前缀和35位置的数还是原来35位置的数,只是排列变化了//排列并不会影响前缀和lower = _lower;upper = _upper;int n = nums.size();dp.resize(n+1);//补了0减少了边界的处理前缀和 presum[i..j] = presum[j] - presum[i - 1] 所以补了0为了减少边界处理temp.resize(n+1);for(int i=1;i<=n;++i) dp[i]=dp[i-1]+nums[i-1];return MergeSort(0,n);}int MergeSort(int left, int right){if (left == right) return 0;int mid = (left + right) >> 1;int ret = 0;ret += MergeSort(left, mid);ret += MergeSort(mid + 1, right);//开始找符合条件的的区间 //升序,固定k 然后用两个指针去索引找到符合要求的地方int k = left, l = mid + 1, r = mid + 1;while (k <= mid){while (l <= right && dp[l] - dp[k] < lower) ++l;while (r <= right && dp[r] - dp[k] <= upper) ++r;ret += (r - l);++k;}//进行合并int cur1 = left, cur2 = mid + 1, i = left;while (cur1 <= mid && cur2 <= right)temp[i++] = dp[cur1] < dp[cur2] ? dp[cur1++] : dp[cur2++];//4、处理没有归并的区间while (cur1 <= mid)   temp[i++] = dp[cur1++];while (cur2 <= right) temp[i++] = dp[cur2++];//5、还原for (int j = left; j <= right; ++j) dp[j] = temp[j];return ret;}
};

十,总结

 分治思想的典型应用就是快速排序和归并排序

1,快速排序本身相当于一个前序遍历,最好的时间复杂度是NlogN 最差的时间复杂度是N^2 ,最坏的情况是出现在(1)以最左侧或最右侧为基准值的时候,凑巧又接近有序(2)大量重复元素。为了解决这个问题衍生出了优化思路:三组划分+随机取key。并且这种方式还可以解决top-k问题,并且时间复杂度是o(N)比堆排序还优秀,我们称之为快速选择算法。

2,归并排序的本质就是将问题划分成无数个合并两个有序数组的子问题。是一个典型的后序遍历,时间复杂度是NlogN.我们发现他有一个特点就是:在归并之前,两个数组是有序的,这个时候我们可以利用他的单调性去做文章。博主总结出来这类的做题思路大概就是,当这个题目涉及到数组种前面的元素和后面的元素存在某种数值上的大小关系(这样才会和单调性建立联系)时,就可以利用归并排序去帮助我们解决。具体需要升序还是降序需要根据题目而定。

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

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

相关文章

ChatGPT加持,需求分析再无难题

简介 在实际工作过程中&#xff0c;常常需要拿到产品的PRD文档或者原型图进行需求分析&#xff0c;为产品的功能设计和优化提供建议。 而使用ChatGPT可以很好的帮助分析和整理用户需求。 实践演练 接下来&#xff0c;需要使用ChatGPT 辅助我们完成需求分析的任务 注意&…

GMSSL-通信

死磕GMSSL通信-C/C++系列(一) 最近再做国密通信的项目开发,以为国密也就简单的集成一个库就可以完事了,没想到能有这么多坑。遂写下文章,避免重复踩坑。以下国密通信的坑有以下场景 1、使用GMSSL guanzhi/GmSSL进行通信 2、使用加密套件SM2-WITH-SMS4-SM3 使用心得 ​…

电动汽车原理视频笔记

看到了一个讲的不错的系列视频 新能源维修猿老罗的个人空间-新能源维修猿老罗个人主页-哔哩哔哩视频 新能源汽车上的安全防护系统就是这么多&#xff01;-绝缘检测等_哔哩哔哩_bilibili 新能源汽车居然是这样上电的-高低压上下电详细流程_哔哩哔哩_bilibili

机器学习和深度学习-- 李宏毅(笔记与个人理解)Day 14

Day 14 Classfication (short version) 二分类的时候 用sigmoid 那不就是 logistic 回归嘛&#xff08;softmax 的二分类等价&#xff09; Loss 哦 今天刚学的 &#xff0c;KL散度 &#xff0c;看来cross-entropy 和KL散度是等价的咯~ 我感觉我的直觉没错 这里MSE离得很远的时候…

php未能在vscode识别?

在设置里搜php&#xff0c;找到settings.json&#xff0c;设置你的安装路径即可。 成功

HubSpot如何通过自动化和优化客户服务流程?

在当今竞争激烈的市场环境中&#xff0c;提供卓越的客户服务体验已经成为企业赢得客户忠诚、推动业务增长的关键所在。HubSpot&#xff0c;作为一款领先的客户关系管理软件&#xff0c;通过自动化和优化客户服务流程&#xff0c;为企业带来了革命性的服务体验提升。 HubSpot通…

【opencv】示例-grabcut.cpp 使用OpenCV库的GrabCut算法进行图像分割

left mouse button - set rectangle SHIFTleft mouse button - set GC_FGD pixels CTRLleft mouse button - set GC_BGD pixels 这段代码是一个使用OpenCV库的GrabCut算法进行图像分割的C程序。它允许用户通过交互式方式选择图像中的一个区域&#xff0c;并利用GrabCut算法尝试…

ruoyi-nbcio-plus基于vue3的flowable的自定义业务显示历史信息组件的升级修改

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 http://122.227.135.243:9666/ 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a…

云LIS系统源码,ASP.NET区域LIS系统源码,实验室信息系统

云LIS系统源码&#xff0c;ASP.NET区域LIS系统源码&#xff0c;实验室信息系统 LIS技术架构&#xff1a;ASP.NET CORE 3.1 MVC SQLserver Redis等 开发语言&#xff1a;C# 6.0、JavaScript 前端框架&#xff1a;JQuery、EasyUI、Bootstrap 后端框架&#xff1a;MVC、S…

大数据架构之关系型数据仓库——解读大数据架构(二)

文章目录 前言什么是关系型数仓对数仓的错误认识与使用自上而下的方法关系型数仓的优点关系型数仓的缺点数据加载加载数据的频率如何确定变更数据 关系型数仓会消失吗总结 前言 本文对关系型数据仓库&#xff08;RDW&#xff09;进行了简要的介绍说明&#xff0c;包括什么是关…

python--递归算法篇

1、给定一个包含n1个整数的数组nums&#xff0c;其数字在1到n之间&#xff08;包含1和n&#xff09;&#xff0c; 可知至少存在一个重复的整数&#xff0c;假设只有一个重复的整数&#xff0c;请找出这个重复的数 def repeat(ls:list) -> list:#把个数超过1的数&#xff0c…

使用geneHapR进行基因单倍型分析(以vcf文件为例)

前记 在群体基因组学研究中&#xff0c;我们常常需要知道一些位点的变异情况&#xff0c;以便于根据对应的表型信息估算这些位点的效应&#xff0c;同时了解这些位点在不同亚群之间的变化情况。这个时候我们就需要进行单倍型分析(Haplotype Analysis)&#xff0c;单倍型分析是研…

Spring Boot | SpringBoot 对 SpringMVC的 “整合支持“

目录: SpringMVC 的 “整合支持” ( 引入"Web依赖启动器"&#xff0c;几乎可以在无任何额外的配置的情况下进行"Web开发")1.SpringMVC "自动配置" 介绍 ( 引入Web依赖启动器"后&#xff0c;SpringBoot会自动进行一些“自动配置”&#xff0…

Linux下mysql的彻底卸载

Linux下mysql的彻底卸载 1、查看mysql的安装情况2、删除上图安装的软件3、都删除成功之后&#xff0c;查找相关的mysql的文件4、删除全部文件5、再次执行命令 1、查看mysql的安装情况 rpm -qa | grep -i mysql2、删除上图安装的软件 rpm -ev mysql-community-libs-5.7.27-1.e…

蓝桥杯 前一晚总结 模板 新手版

《准备实足&#xff0c;冲冲冲 省一》https://www.yuque.com/lenyan-svokd/hi7hp2/hfka297matrtsxy2?singleDoc# 《准备实足&#xff0c;冲冲冲 省一》 #include<bits/stdc.h> // 包含标准库头文件using namespace std; using ll long long; // 定义 long long 数据类…

【opencv】示例-opencv_version.cpp 输出OpenCV的版本和构建配置的示例

#include <opencv2/core/utility.hpp> // 引入OpenCV核心工具库 #include <iostream> // 引入标准输入输出流库// 定义一个包含命令行参数的字符串 static const std::string keys "{ b build | | print complete build info }" // 定义参数b&#xff…

【数据结构】06图

图 1. 定义1.1 无向图和有向图1.2 度、入度和出度1.3 图的若干定义1.4 几种特殊的图 2. 图的存储2.1 邻接矩阵-顺序存储&#xff08;数组&#xff09;2.2 邻接表-顺序存储链式存储&#xff08;数组链表&#xff09;2.3 十字链表-适用于有向图2.4 邻接多重表-适用于无向图 3. 图…

设计模式代码实战-建造者模式

1、问题描述 小明家新开了一家自行车工厂&#xff0c;用于使用自行车配件&#xff08;车架 frame 和车轮 tires &#xff09;进行组装定制不同的自行车&#xff0c;包括山地车和公路车。 山地车使用的是Aluminum Frame&#xff08;铝制车架&#xff09;和 Knobby Tires&#x…

【随笔】Git 高级篇 -- 管理多分支 git rebase(二十二)

&#x1f48c; 所属专栏&#xff1a;【Git】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &#x1f496; 欢迎大…

PyTorch环境配置问题

为什么深度学习都是用英伟达的显卡&#xff1f; 首先我们需要了解什么是CUDA&#xff1f; CUDA&#xff08;Compute Unified Device Architecture&#xff09;&#xff0c;是显卡厂商 NVIDIA 推出的运算平台。 CUDA就类似于编程语言&#xff0c;开发者和显卡通过CUDA进行交流…