欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 游戏 > 【优选算法】——分治-快速归并排序!

【优选算法】——分治-快速归并排序!

2025/2/25 0:06:17 来源:https://blog.csdn.net/2301_80221228/article/details/144437367  浏览:    关键词:【优选算法】——分治-快速归并排序!

目录

1、颜色分类

 2、快速排序

3、数组中的第K个最大元素

4、库存管理III

5、排序数组

6、交易逆序对的总数

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

8、翻转对


1、颜色分类

给定一个包含红色、白色和蓝色、共 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(vector<int>& nums) {int key=1,i=0,left=-1,right=nums.size();while(i<right){if(nums[i]<key) swap(nums[++left],nums[i++]);else if(nums[i]==key) i++;else swap(nums[--right],nums[i]);}}
};

 2、快速排序

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

你必须在 不使用任何内置函数 的情况下解决问题,时间复杂度为 O(nlog(n)),并且空间复杂度尽可能小。

示例 1:

输入:nums = [5,2,3,1]
输出:[1,2,3,5]

示例 2:

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

class Solution {
public:vector<int> tmp;//定义全局的辅助数组帮组归并排序vector<int> sortArray(vector<int>& nums) {tmp.resize(nums.size());mergesort(nums,0,nums.size()-1);return nums;}void mergesort(vector<int>& nums,int left,int right){//递归结束条件if(left>=right) return;//选择中间开始递归 [left,mid] [mid+1,right]int mid=left+(right-left)/2;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]) tmp[i++]=nums[cur1++];else tmp[i++]=nums[cur2++];}//解决没有排序的数据while(cur1<=mid) tmp[i++]=nums[cur1++];while(cur2<=right) tmp[i++]=nums[cur2++];//将辅助数组的数据拷贝到原数组for(int i=left;i<=right;i++)nums[i]=tmp[i-left];}
};

3、数组中的第K个最大元素

给定整数数组 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(vector<int>& nums, int k) {srand(time(NULL));return qsort(nums,0,nums.size()-1,k);}int qsort(vector<int>& nums,int l,int r,int k){if(l==r) return nums[l];//随机选keyint key=getKey(nums,l,r);//数组分三块int i=l,left=l-1,right=r+1;while(i<right){if(nums[i]<key) swap(nums[++left],nums[i++]);else if(nums[i]==key) i++;else swap(nums[--right],nums[i]);}//在三个区间内找第k大 [l,left] [left+1,right-1] [right,r]int a=r-right+1,b=right-left-1;if(a>=k) return qsort(nums,right,r,k);else if(a+b>=k) return key;else return qsort(nums,l,left,k-a-b);}int getKey(vector<int>& nums,int l,int r){return nums[rand()%(r-l+1)+l];}
};

4、库存管理III

仓库管理员以数组 stock 形式记录商品库存表,其中 stock[i] 表示对应商品库存余量。请返回库存余量最少的 cnt 个商品余量,返回 顺序不限

示例 1:

输入:stock = [2,5,7,4], cnt = 1
输出:[2]

示例 2:

输入:stock = [0,2,3,6], cnt = 2
输出:[0,2] 或 [2,0]

class Solution {
public: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 l,int r,int k){if(l>=r) return;//随机选keyint key=GetKey(nums,l,r);//数组分三块int i=l,left=l-1,right=r+1;while(i<right){if(nums[i]<key) swap(nums[++left],nums[i++]);else if(nums[i]==key) i++;else swap(nums[--right],nums[i]);}//[l,left] [left+1,right-1] [right,l]int a=left-l+1,b=right-left-1;if(a>k) qsort(nums,l,left,k);else if(a+b>=k) return;else qsort(nums,right,r,k-a-b);}int GetKey(vector<int>& nums,int l,int r){return nums[l+(rand()%(r-l+1))];}
};

5、排序数组

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

你必须在 不使用任何内置函数 的情况下解决问题,时间复杂度为 O(nlog(n)),并且空间复杂度尽可能小。

示例 1:

输入:nums = [5,2,3,1]
输出:[1,2,3,5]

示例 2:

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

class Solution {
public:vector<int> tmp;//定义全局的辅助数组帮组归并排序vector<int> sortArray(vector<int>& nums) {tmp.resize(nums.size());mergesort(nums,0,nums.size()-1);return nums;}void mergesort(vector<int>& nums,int left,int right){//递归结束条件if(left>=right) return;//选择中间开始递归 [left,mid] [mid+1,right]int mid=left+(right-left)/2;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]) tmp[i++]=nums[cur1++];else tmp[i++]=nums[cur2++];}//解决没有排序的数据while(cur1<=mid) tmp[i++]=nums[cur1++];while(cur2<=right) tmp[i++]=nums[cur2++];//将辅助数组的数据拷贝到原数组for(int i=left;i<=right;i++)nums[i]=tmp[i-left];}
};

6、交易逆序对的总数

在股票交易中,如果前一天的股价高于后一天的股价,则可以认为存在一个「交易逆序对」。请设计一个程序,输入一段时间内的股票交易记录 record,返回其中存在的「交易逆序对」总数。

示例 1:

输入:record = [9, 7, 5, 4, 6]
输出:8
解释:交易中的逆序对为 (9, 7), (9, 5), (9, 4), (9, 6), (7, 5), (7, 4), (7, 6), (5, 4)。

class Solution {
public:vector<int> tmp;int reversePairs(vector<int>& nums) {tmp.resize(nums.size());return mergesort(nums,0,nums.size()-1);}int mergesort(vector<int>& nums,int left,int right){if(left>=right) return 0;int ret=0;int mid=left+(right-left)/2;//左右俩边各找一下ret+=mergesort(nums,left,mid);ret+=mergesort(nums,mid+1,right);//归并排序(此时左右两边都是升序),顺便左右两边找一下逆序对int i=0,cur1=left,cur2=mid+1;while(cur1<=mid&&cur2<=right) {if(nums[cur1]>nums[cur2]){tmp[i++]=nums[cur1++];ret+=right-cur2+1;}else {tmp[i++]=nums[cur2++];}}while(cur1<=mid) tmp[i++]=nums[cur1++];while(cur2<=right) tmp[i++]=nums[cur2++];for(int i=left;i<=right;i++){nums[i]=tmp[i-left];}return ret;}
};

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

给你一个整数数组 nums ,按要求返回一个新数组 counts 。数组 counts 有该性质: counts[i] 的值是  nums[i] 右侧小于 nums[i] 的元素的数量。

示例 1:

输入:nums = [5,2,6,1]
输出:[2,1,1,0] 
解释:
5 的右侧有 2 个更小的元素 (2 和 1)
2 的右侧仅有 1 个更小的元素 (1)
6 的右侧有 1 个更小的元素 (1)
1 的右侧有 0 个更小的元素

示例 2:

输入:nums = [-1]
输出:[0]

示例 3:

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

class Solution {
public://ret记录结果,index记录下标,tmp1辅助排序,tmp2辅助index跟随排序vector<int> ret,tmp1,tmp2,index;vector<int> countSmaller(vector<int>& nums) {int n=nums.size();ret.resize(n);tmp1.resize(n);tmp2.resize(n);//index初始化原数组下标index.resize(n);for(int i=0;i<n;i++) index[i]=i;mergesort(nums,0,n-1);return ret;}void mergesort(vector<int>& nums,int left,int right){if(left>=right) return;int mid=left+(right-left)/2;mergesort(nums,left,mid);mergesort(nums,mid+1,right);int i=0,cur1=left,cur2=mid+1;while(cur1<=mid&&cur2<=right) {if(nums[cur1]>nums[cur2]) {ret[index[cur1]]+=right-cur2+1;//更新结果(当前值的结果要放到其原始下标的位置)tmp1[i]=nums[cur1];//值放入辅助数组tmp2[i++]=index[cur1++];//当前值的下标放入辅助数组}else {tmp1[i]=nums[cur2];tmp2[i++]=index[cur2++];}}//解决剩余排序问题while(cur1<=mid) {tmp2[i]=index[cur1];tmp1[i++]=nums[cur1++];}while(cur2<=right) {tmp2[i]=index[cur2];tmp1[i++]=nums[cur2++];}for(int i=left;i<=right;i++){nums[i]=tmp1[i-left];index[i]=tmp2[i-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

class Solution {
public:vector<int> tmp;int reversePairs(vector<int>& nums) {tmp.resize(nums.size());return mergesort(nums,0,nums.size()-1);}int mergesort(vector<int>& nums,int left,int right){if(left>=right) return 0;int ret=0;int mid=left+(right-left)/2;//左右俩边各找一下ret+=mergesort(nums,left,mid);ret+=mergesort(nums,mid+1,right);//在归并前找翻转对(数组有序,同向双指针)int i=0,cur1=left,cur2=mid+1;while(cur1<=mid&&cur2<=right) {if(nums[cur1]>2*(long long)nums[cur2]){ret+=right-cur2+1;cur1++;}else cur2++;}//归并排序i=0,cur1=left,cur2=mid+1;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(int i=left;i<=right;i++){nums[i]=tmp[i-left];}return ret;}
};

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词