分而治之:指的是当主问题可以被分解为一个相同次级问题加相同基本问题时,采用这种思想,基本问题指问题规模最小时的情况,次级问题是指主问题的n级降低n-1级的问题。
具体实现:多数采用递归操作分解,然后递归操作,需要注意的是函数头,函数体,以及递归出口,函数头:由问题所需变量指定,递归出口由问题最小规模返回决定,函数体看问题具体的需要的信息决定。
class Solution {
public:
void sortColors(vector<int>& nums) {
int left=-1;int right=nums.size();
int cur=0;
while(cur<right){
if(nums[cur]==0) swap(nums[++left],nums[cur++]);
else if(nums[cur]==2) swap(nums[--right],nums[cur]);
else cur++;
}
return ;
}
};
分治-快速排序:下面这三题:都是快排,其中第一题快排,第二题,在快排的基础上,进行剪枝,避免无用的排序,第三题同理,也是避免无用排序。通过设置进入那个递归来实现。
class Solution { public: vector<int> sortArray(vector<int>& nums) { srand(time(0)); sort1(nums,0,nums.size()-1); return nums; } void sort1(vector<int>& nums,int left,int right){ if(left>=right) return;// int key=Getrand(nums,left,right); //swap(nums[left],key);Ⅲ、交换会覆盖一个,不是交换 int cur=left; int l=left-1; int r=right+1; while(cur<r){//Ⅱ、cur判断数据时,之后可能会越界,所以一次只能判断一个条件,然后需要判断cur<r,不能多个if。 if(nums[cur]>key) swap(nums[cur],nums[--r]); else if(nums[cur]<key) swap(nums[cur++],nums[++l]); else if(nums[cur]==key) cur++; } sort1(nums,left,l); sort1(nums,r,right); } int Getrand(vector<int>& nums,int left,int right){ int rd=rand(); return nums[rd%(right-left+1)+left]; //Ⅰ:记得+left,否则超范围, } };
215. 数组中的第K个最大元素 - 力扣(LeetCode)
数组中第k个最大元素,①:快速选择,利用快排思想(三路划分),实现O(n),②:利用优先队列(堆):找大的就是用小根堆。找小的用大根堆。O(Nlog2k);
class Solution { public: int findKthLargest(vector<int>& nums, int k) { srand(time(0)); return qsort(nums,0,nums.size()-1,k); } int qsort(vector<int>& nums,int l,int r,int k){ int key=GetRand(nums,l,r); int cur=l; int left=l-1;int right=r+1; while(cur<right){ if(nums[cur]>key) swap(nums[cur++],nums[++left]); else if(nums[cur]<key) swap(nums[cur],nums[--right]); else cur++; } int a=left-l+1; int b=cur-left-1;int c=r-right+1; if(k<=a) return qsort(nums,l,left,k); else if(k>a&&k<=a+b) return key; else return qsort(nums,right,r,k-a-b); } int GetRand(vector<int>& nums,int l,int r){ int rd=rand(); return nums[rd%(r-l+1)+l]; } };
LCR 159. 库存管理 III - 力扣(LeetCode)
class Solution { public: vector<int> inventoryManagement(vector<int>& stock, int cnt) {//如何提取区间 srand(time(0)); qsort(stock,0,stock.size()-1,cnt); return vector<int>(stock.begin(),stock.begin()+cnt); } void qsort(vector<int>& stock,int l,int r,int cnt){ if(l>=r) return ;//若没有则,getrand会出错;%0错误。 int key=GetRand(stock,l,r); int cur=l,left=l-1,right=r+1; while(cur<right){ if(stock[cur]<key) swap(stock[cur++],stock[++left]); else if(stock[cur]>key) swap(stock[cur],stock[--right]); else cur++; } int a=left-l+1; int b=right-left-1; int c=r-right+1; if(cnt<=a) qsort(stock,l,left,cnt); else if(cnt<=a+b) return ; else qsort(stock,right,r,cnt-a-b); } int GetRand(vector<int>& stock,int l,int r){ int rd=rand(); return stock[rd%(r-l+1)+l]; } };
分治——归并排序
class Solution {
vector<int> tmp;
public:
vector<int> sortArray(vector<int>& nums) {//归并
tmp.resize(nums.size());
MageSort(nums,0,nums.size()-1);
return nums;
}
void MageSort(vector<int>& nums,int l,int r){
if(l>=r) return;
int mid=l+(r-l)/2;
MageSort(nums,l,mid);
MageSort(nums,mid+1,r);
int cur1=l;int cur2=mid+1;int cur=l;
while(cur1<=mid&&cur2<=r){
if(nums[cur1]<=nums[cur2]){
tmp[cur++]=nums[cur1++];
}else if(nums[cur1]>nums[cur2]){
tmp[cur++]=nums[cur2++];
}
}
while(cur1<=mid) tmp[cur++]=nums[cur1++];
while(cur2<=r) tmp[cur++] =nums[cur2++];
//拷贝回去
int left=l,right=r;
while(left<=right) {
nums[left]=tmp[left];//*****只有一个left++,首先执行”=“左边的那个部分语句,所有left拷贝给left+1.
left++;
}
return;
}
};
LCR 170. 交易逆序对的总数 - 力扣(LeetCode)
class Solution {
vector<int> tmp;
public:
int reversePairs(vector<int>& record) {
int ret=0;
tmp.resize(record.size());
return magesort(record,0,record.size()-1,ret);
}
int magesort(vector<int>& record ,int left,int right,int& ret){
if(left>=right) return 0;
int mid=left+(right-left)/2;
magesort(record,left,mid,ret);
magesort(record,mid+1,right,ret);
int cur=left; int cur1=left,cur2=mid+1;
while(cur1<=mid&&cur2<=right){
if(record[cur1]<=record[cur2]) tmp[cur++]=record[cur2++];//降序。
else{
ret+=right-cur2+1;//****记录左边数组的每个值对应的,右边小于它的个数,right-cur2+1是降序
tmp[cur++]=record[cur1++];
}
}
while(cur1<=mid) tmp[cur++]=record[cur1++];
while(cur2<=right) tmp[cur++]=record[cur2++];
//拷贝回去,复原
for(int i=left;i<=right;i++){//*****拷贝要left到right。完整一段
record[i]=tmp[i];
}
return ret;
}
};
315. 计算右侧小于当前元素的个数 - 力扣(LeetCode)
class Solution {
vector<int> tmp;
vector<int> tmp_index;
vector<int> index;
vector<int> ret;
public:
vector<int> countSmaller(vector<int>& nums) {
ret.resize(nums.size());
index.resize(nums.size());
for(int i=0;i<nums.size();i++){//建立变换后的下标[i]与原下标i之间的映射
index[i]=i;
}
tmp.resize(nums.size());
tmp_index.resize(nums.size());
MageSort(nums,0,nums.size()-1);
return ret;
}
void MageSort(vector<int>& nums,int left,int right){
if(left>=right) return;
int mid=left+(right-left)/2;
MageSort(nums,left,mid);
MageSort(nums,mid+1,right);
int cur=left;int cur1=left; int cur2=mid+1;
while(cur1<=mid&&cur2<=right){
if(nums[cur2]<nums[cur1]){//降序,求右区间小于cur1的个数
ret[index[cur1]]+=right-cur2+1;
tmp[cur]=nums[cur1];
tmp_index[cur++]=index[cur1++];//**1***保持映射
}else{
tmp[cur]=nums[cur2];
tmp_index[cur++]=index[cur2++];
}
}
while(cur1<=mid) {
tmp[cur]=nums[cur1];
tmp_index[cur++]=index[cur1++];
}
while(cur2<=right){
tmp[cur]=nums[cur2];//**1**多加了++
tmp_index[cur++]=index[cur2++];
}
//还原
for(int i=left;i<=right;i++){
nums[i]=tmp[i];
index[i]=tmp_index[i];
}
}
};
class Solution {
int ret=0;
vector<int> tmp;
public:
int reversePairs(vector<int>& nums) {
int n=nums.size();
tmp.resize(n);
MageSort(nums,0,n-1);
return ret;
}
void MageSort(vector<int>& nums,int left,int right){
if(left>=right) return ;
int mid=(left+right)>>1;
MageSort(nums,left,mid);
MageSort(nums,mid+1,right);
int cur1=left; int cur2=mid+1;
while(cur1<=mid&&cur2<=right){
// cout<<left<<" "<<mid<<" "<<mid+1<<" "<<right<<endl;//**1**打印也会出现超时的错误
// cout<<nums[cur1]/2.0<<" "<<nums[cur2]<<endl;
if(nums[cur1]/2.0>nums[cur2]){//**2***一定要2.0,否则会出现3/2不大于1的情况,降序
ret+=right-cur2+1;
cur1++;
}else{
cur2++;
}
}
int cur=left; cur1=left; cur2=mid+1;
while(cur1<=mid&&cur2<=right){
if(nums[cur1]>=nums[cur2]){
tmp[cur++]=nums[cur1++];
}else{;
tmp[cur++]=nums[cur2++];
}
}
while(cur1<=mid)
tmp[cur++]=nums[cur1++];
while(cur2<=right)
tmp[cur++]=nums[cur2++];
//还原
for(int i=left;i<=right;i++){
nums[i]=tmp[i];
}
return ;
}
};