发布时间:2025-06-24 19:57:51 作者:北方职教升学中心 阅读量:453
这里使用的思想就是数组划分三段。归并排序
归并排序,也用到了递归思想。因为这道题本身要求是返回一个升序数数列。

代码片:
classSolution{public:voidsortColors(vector<int>&nums){intn=nums.size();intleft=-1,right=n,i=0;while(i<right){if(nums[i]==0)swap(nums[++left],nums[i++]);elseif(nums[i]==1)i++;elseif(nums[i]==2)swap(nums[--right],nums[i]);}}};
1.2数组中第k个最大元素
数组中的第k个最大元素
这里使用的快排的思想。。题目要求求第k大元素,这个k可能落在这三个其中某一块区域。那么cur2后面的数肯定也比cur1小。我们先选个随机标准数key,根据key值将数组分三块,小于key值放最左边,等于key值放右边,大于key值放最右边。[left,mid] [mid+1,right].定义俩指针 cur1 、归并排序的空间复杂度:O(n),因为在合并过程中需要额外的空间来存储临时数组。所以我们直接在合并俩有序数组这一步处理,如果cur1小于cur2值,将nums[cur1]赋给新数组,然后cur1向后移动,移动到一个新数,再去比较。

classSolution{vector<int>tmp;public:intreversePairs(vector<int>&nums){tmp.resize(nums.size());returnmergesort(nums,0,nums.size()-1);}intmergesort(vector<int>&nums,intleft,intright){if(left>=right)return0;intret=0;intmid=(left+right)>>1;ret+=mergesort(nums,left,mid);ret+=mergesort(nums,mid+1,right);intcur1=left,cur2=mid+1,i=0;while(cur1<=mid &&cur2<=right){if(nums[cur1]<=nums[cur2])tmp[i++]=nums[cur1++];else{ret+=mid-cur1+1;tmp[i++]=nums[cur2++];}}

一、 否则,反之。然后继续向后走。" />1 .1颜色分类
颜色分类

由于本体只会出现3个数字,并且结果要求输出 0,1,2这样的。(因为最右边都是大的元素,大的元素有c个,如果第k大比c小的话,那第k大元素一定落在该区域)。 很容易解出来。剩下的操作都是归并排序里通用的思路。快排
二、让这三段分别小于key,等于key,大于key.
快排
使用快排的思想就是 将一段区域分为3段,在选取一个基准元素key。找到该数了 并且cur1后面的值肯定都比cur2指向的值大。
分类讨论,遍历时候 如果nums[i]是0的话,交换swap(nums[++left],nums[i]) 并且都向后移动;如果是1,不用交换,i++继续向后移动;如果是2,交换右边的跟当前的swap(nums[right–],nums[i]),此时i不用向后移动,继续对当前交换后的数进行判断。cur2,分别指向left和right.一直遍历循环。说明cur2指向的值第一次比他大,cur1继续向后走, 当cur1指向的值比cur2大。找到该数之前,统计有多少个数比我大。一段区间,选取中间点,分别从左右两区间排序(根据题目要求决定升序降序),排序完之后合并俩有序数组,再返回上一层。直到不走出边界位置。统计个数。
2.1排序数组
排序数组
题目描述:

讲解篇:
本体讲解下归并的方法。因为找的时候对数组降序排序了。定义3个指针,i指针遍历数组,left指针标记最左侧。b+c>=k,返回key值。

classSolution{inttmp[50010];public:intreversePairs(vector<int>&nums){returnmergesort(nums,0,nums.size()-1);}intmergesort(vector<int>&nums,intleft,intright){if(left>=right)return0;intres=0;intmid=(left+right)>>1;res+=mergesort(nums,left,mid);res+=mergesort(nums,mid+1,right);intcur1=left,cur2=mid+1,i=left;while(cur1<=mid){while(cur2<=right&&nums[cur2]>=nums[cur1]/2.0)cur2++;if(cur2>right)break;res+=right-cur2+1;cur1++;}cur1=left,cur2=mid+1;while(cur1<=mid&&cur2<=right){tmp[i++]=nums[cur1]<=nums[cur2]?nums[cur2++]:nums[cur1++];}while(cur1<=mid)tmp[i++]=nums[cur1++];while(cur2<=right)tmp[i++]=nums[cur2++];for(intj=left;j<=right;j++){nums[j]=tmp[j];}returnres;}};
2.3交换逆序对总数
交换逆序对的总数

题目解析:
这里其实意思就是求数组中的逆序对个数。如果c>=k,在【right,r】区间找第k大元素。
草图:

代码篇:
classSolution{public:intfindKthLargest(vector<int>&nums,intk){srand(time(NULL));returnqsort(nums,0,nums.size()-1,k);}intqsort(vector<int>&nums,intl,intr,intk){if(l==r)returnnums[l];intkey=getRodm(nums,l,r);intleft=l-1,right=r+1,i=l;while(i<right){if(nums[i]<key)swap(nums[++left],nums[i++]);elseif(nums[i]==key)i++;elseswap(nums[--right],nums[i]);}intb=right-left-1,c=r-right+1;if(c>=k)returnqsort(nums,right,r,k);elseif(b+c>=k)returnkey;elsereturnqsort(nums,l,left,k-b-c);}intgetRodm(vector<int>&nums,intleft,intright){intr=rand();returnnums[r%(right-left+1)+left];}};
1.3
二、但是对于不同的题,具体问题得具体分析。处理下排序while(cur1<=mid)tmp[i++]=nums[cur1++];while(cur2<=right)tmp[i++]=nums[cur2++];for(intj=left;j<=right;j++){nums[j]=tmp[j-left];}returnret;}};
总结;
我们在写归并排序题时候会发现都会有相同之处。当cur2当前的值比cur1当前的值大或者等于。方法还是归并排序。 cur2,分别指向两个区域的开始位置。
这里使用的是归并的思想。合并两个有序数组intcur1=left,cur2=mid+1,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(inti=left;i<=right;i++){nums[i]=tmp[i-left];}}};
2.2翻转对
翻转对
本题的解题思路用到的是归并法。以上都不成立,就在第一个区间找第k-b-c大元素(因为我们要在整个区间找第k大元素,但是大元素都不是我们要的结果,接下来在这个小区间时候,要把大区间元素个数抛弃掉)。如果刚好比cur1小。
快排算法篇
- 一、
草图:

代码篇:
classSolution{vector<int>tmp;public:vector<int>sortArray(vector<int>&nums){tmp.resize(nums.size());mergesort(nums,0,nums.size()-1);returnnums;}voidmergesort(vector<int>&nums,intleft,intright){if(left>=right)return;intmid=(left+right)>>1;mergesort(nums,left,mid);mergesort(nums,mid+1,right);