【LeetCode热题100】分治-归并

server/2024/10/21 8:11:55/

这篇博客记录了分治-归并的几道题目,包括排序数组、逆序对、计算右侧小于当前元素的个数、翻转对这几道题目。

//归并排序
class Solution 
{//创建一个全局变量,这样可以提高效率vector<int> tmp;
public:void _sortArray(vector<int>& nums,int left,int right){if(left >= right) return;//1.选择中间点划分区间int mid = left + (right - left)/2;//[left,mid] [mid+1,right]//2.把左右区间排序_sortArray(nums,left,mid);_sortArray(nums,mid+1,right);//3.合并两个有序数组int p1 = left,p2 = mid+1,i=0;while(p1 <= mid && p2 <= right)tmp[i++] = nums[p1]<=nums[p2]?nums[p1++]:nums[p2++];//4.处理没有遍历的数组while(p1 <= mid) tmp[i++] = nums[p1++];while(p2 <= right) tmp[i++] = nums[p2++];//5.还原for(int i = left ; i <= right ; i++){nums[i] = tmp[i-left];}}vector<int> sortArray(vector<int>& nums) {tmp.resize(nums.size());_sortArray(nums,0,nums.size()-1);return nums;}};

题目分析:我们可以归并排序,归并排序的思想就是先找一个中间值,然后把其左边区间也归并排序,然后其右边区间也归并排序,然后再把两个排序好的左右两个有序数组合并,合并两个有序数组的思路是双指针,分别指向左右区间的起始,另创建一个空数组,比较这两个指针指向的元素大小,小的放进这个空数组,直到遍历完。

所以,归并排序类似二叉树的后序遍历,而快速排序类似二叉树的前序遍历

class Solution {int v[50001];
public:int MergeSort(vector<int>& nums,int left,int right){if(left >= right) return 0;//1.找中间点,将数组分成两部分//int mid = left+(right-left)/2;int mid = (left + right) >> 1;//[left,mid] [mid+1,right] 升序int ret = 0;//2.左边的个数+排序 右边的个数+排序ret += MergeSort(nums,left,mid);ret += MergeSort(nums,mid+1,right);int cur1 = left,cur2 = mid+1,i=0;//3.一左一右的个数while(cur1 <= mid && cur2 <= right){if(nums[cur1] > nums[cur2]) {   ret += mid - cur1 + 1;v[i++] = nums[cur2++];}else{v[i++] = nums[cur1++];}}// while(cur1 <= mid && cur2 <= right) v[i++] = nums[cur1] < nums[cur2] ? nums[cur1] : nums[cur2];while(cur1 <= mid) v[i++] = nums[cur1++];while(cur2 <= right) v[i++] = nums[cur2++];for(int i = left ; i <= right ; i++){nums[i] = v[i-left];}return ret;}int reversePairs(vector<int>& record) {return MergeSort(record,0,record.size()-1);}
};

题目分析:我们可以使用归并排序解决这道题,将数组分为两部分,左半部分->排序->右半部分->排序->一左一右,其中我们在一左一右中找逆序对时,只需要固定右半部分一个值,然后去左半部分找有多少大于这个值的元素,这种方法要求归并排序是升序

也可以固定左半部分一个值,然后去右半部分找有多少小于这个值的元素,这种方法要求归并排序是降序

假设是升序,在将数组分成一左一右后,[left,mid][mid+1,right],cur1和cur2分别遍历这两部分,nums[cur1]和nums[cur2]的大小关系有两种情况,

1)nums[cur1] <= nums[cur2],cur1++

2)nums[cur1] > nums[cur2],ret += mid - cur1+1,cur2++

class Solution {vector<int> ret;vector<int> nums_tmp;int index[500010];int index_tmp[500010];public:void MergeSort(vector<int>& nums,int left,int right){if(left >= right) return;int mid = (left + right) >> 1;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]){ret[index[cur1]] += (right - cur2 + 1);index_tmp[i] = index[cur1];nums_tmp[i++] = nums[cur1++];}else{index_tmp[i] = index[cur2];nums_tmp[i++] = nums[cur2++];}}while(cur1 <= mid){index_tmp[i] = index[cur1];nums_tmp[i++] = nums[cur1++];}while(cur2 <= right){index_tmp[i] = index[cur2];nums_tmp[i++]= nums[cur2++];}for(int i = left; i <= right ; i++){nums[i] = nums_tmp[i-left];index[i] = index_tmp[i-left];}}vector<int> countSmaller(vector<int>& nums) {ret.resize(nums.size());nums_tmp.resize(nums.size());for(int i = 0; i < nums.size() ; i++){index[i]=i;}MergeSort(nums,0,nums.size()-1);return ret;}
};

题目分析:我们要找出之后有多少元素比我小,依照上题思路,需要选择降序,也是采用分支排序的方法,

为了找到对应的下标,刚开始就要创建一个数组index,里面是各个元素下表,在排序过程中,index也要跟着nums元素位置变化而变化。

class Solution {//vector<int> tmp;int tmp[50010];
public:int _reversePairs(vector<int>& nums,int left,int right){if(left >= right) return 0;int ret = 0;int mid = (left + right)>>1;ret += _reversePairs(nums,left,mid);ret += _reversePairs(nums,mid+1,right);int cur1 = left,cur2 = mid+1;//1.先找翻转对的数量while(cur1 <= mid && cur2 <= right){if(0.5*nums[cur1] > nums[cur2]){ret += (right - cur2 + 1);cur1++;}else{cur2++;}}//2.合并两个有序数组cur1 = left,cur2=mid+1;int 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++];for(i = left; i <= right ; i++){nums[i] = tmp[i-left];}return ret;}int reversePairs(vector<int>& nums) {//tmp.resize(nums.size());return _reversePairs(nums,0,nums.size()-1);   }
};

题目分析:这道题我们依然用分治的思想。将一个数组分成两部分,先找左半部分的翻转对,再找右半部分的翻转对,最后再找一左一右的翻转对。

仍然有两个策略

1)计算当前元素后面,有多少元素的两倍比我少,要求数组降序。

if(nums[cur1] > 2*nums[cur2]) ret += right-cur2+1

2)计算当前元素之前,有多少元素的一半比我大,要求数组升序。

if(nums[cur1] > 2*nums[cur2]) ret += mid-left+1


http://www.ppmy.cn/server/133586.html

相关文章

Vue 3 的不同版本总结

Vue 3 的不同版本&#xff08;例如 3.x 系列的多个次版本&#xff09;在语法和特性上有一些变化和改进。以下是 Vue 3 中随着版本迭代的一些语法变化和新特性的总结。 1. Vue 3.0: 初始发布 主要特性&#xff1a; 组合式 API (Composition API)&#xff1a;引入 setup 函数&…

小米等手机彻底关闭快应用

文章目录 快应用的是非最终措施&#xff1a;撤销快应用隐私协议配套措施&#xff1a;安卓去除开屏广告 无用的操作&#xff1a;载快应用小米手机无用&#xff0c;其他手机可以尝试的操作关闭唤起快应用服务打开防止误触、后台启动其他应用 其他措施&#xff1a;冻结、加密快应用…

服务攻防之Redis数据库安全

最近我将会把一些服务攻防方面的姿势在这里做一个简单总结。欢迎大家留言讨论。 首先我们先对这类安全问题做一个总体的概括&#xff01; 一、总概 1.服务判断: 端口扫描&#xff1a;利用服务开启后的目标端口开放判断 组合判断&#xff1a;利用搭建常见组合分析可能开放服务…

使用Maven前的简单准备

目录 一、Maven的准备 1、安装jdk1.8或以上版本 2、下载Maven 3、安装Maven 二、Maven目录的分析 三、Maven的环境变量配置 1、设置MAVEN_HOME环境变量 2、设置Path环境变量 3、验证配置是否完成 一、Maven的准备 1、安装jdk1.8或以上版本 jdk的安装 2、下载Maven…

ElementPlus-Table表格-单选--TypeScript进阶篇

今天看个例子&#xff0c;这个例子是ElementPlus的组件Table表格下面的单选 <template> <el-table ref"singleTableRef" :data"tableData" highlight-current-row style"width: 100%" current-change"hand…

IntelliJ IDEA中配置scala

1.IDEA中 配置 maven 左上角 file -> Setting 选择(或直接搜maven) Build, Execution,Deployment -> Build Toos -> Maven Maven home path 选择 maven 安装目录&#xff08;bin的上层目录&#xff09; 示例&#xff1a; D:\maven\apache-maven-3.8.6 User settings…

从 Microsoft 官网下载 Windows 10

方法一&#xff1a; 打开 Microsoft 官网&#xff1a; 打开开发人员工具&#xff08;按 F12 或右键点击“检查”&#xff09;。 点击“电脑模拟手机”按钮&#xff0c;即下图&#xff1a; 点击后重新加载此网页&#xff0c;即可看到下载选项。

Midjourney中文版:创意无界,绘梦成真

在数字艺术的浩瀚宇宙中&#xff0c;Midjourney中文版如同一颗璀璨的新星&#xff0c;以其独特的魅力和无限可能&#xff0c;引领着每一位创作者探索创意的无限边界。作为专为国内用户打造的AI绘画工具&#xff0c;Midjourney中文版不仅继承了原版的核心优势&#xff0c;更在本…