算法复习:快排
leedcode 215. 数组中的第K个最大元素
快排每次寻找都会确定一个元素的真实位置
快排的思想:
先定第一个位置是坑,取出第一个位置的值作为最终要确定位置的值,设置up指针和down指针
由于一开始坑的位置和up重合,直接判断坑的值和down的值大小,此时坑>down需要换坑位置,交换以后down的值付给原来的坑,新坑的位置和down重合,up后移一个
再比较,up<坑,继续后移up一个单位;此时up>坑,需要换坑的位置,此时的up值赋给旧坑,up的位置变成新坑,以此类推。
快排双指针挖坑法,递归代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<vector> #include<string> #include<algorithm> #include<stdlib.h> #include<set> #include<map> using namespace std; #define MAX 999999 #define CLR(arr,what) memset(arr,what,sizeof(arr)) void make_sit(vector<int>&donser,int start,int end) { if(start==end) return ; int str_x=start,str_y=end,pare=donser[start];//str_x头指针 str_y尾指针 pares坑值 int lable=0;//=0指示坑在前 =1指示坑在后 while(str_x!=str_y) { if(lable==0) { if(pare<=donser[str_y]) { str_y--; continue; } else { lable=1;//坑移到后面 donser[str_x]=donser[str_y]; donser[str_y]=pare; str_x++; continue; } } else if(lable==1) { if(pare>=donser[str_x]) { str_x++; continue; } else { lable=0;//坑移到前面 donser[str_y]=donser[str_x]; donser[str_x]=pare; str_y--; continue; } } } //此时str_x==str_y正是确定了位置的一个元素,递归 if(start<=str_x-1) make_sit(donser,start,str_x-1); if(str_x+1<=end) make_sit(donser,str_x+1,end); return; } void quick_sort(vector<int>&donser)//从小到大排 { int start=0,end=donser.size()-1; make_sit(donser,start,end); return; } int main() { vector<int>donser; int N; cin>>N; while(N--) { int tmp; cin>>tmp; donser.push_back(tmp); } quick_sort(donser); for(int i=0;i<donser.size();i++) cout<<donser[i]; cout<<endl; return 0; } /* 5 5 9 3 4 6 */
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
void quick_sort(vector<int>&num,int start,int end) { int head=start,tail=end,hole=start;//头指针 尾指针 坑 。初始 head=start,tail=end,hole=start int tmp_cmp=num[hole];//取出第一个坑处元素值//坑可能在头处,可能在尾处,初始在头处 while(head<tail)//终止条件 { if(hole==head)//坑在头处,和尾指针比较 { if(tmp_cmp>num[tail])//tail处小,交换坑的位置 { num[hole]=num[tail]; hole=tail; head++; } else//tail处大,移动tail的位置 { tail--; } } else if(hole==tail)//坑在尾处,和头指针比较 { if(tmp_cmp<num[head])//head处大,交换坑的位置 { num[hole]=num[head]; hole=head; tail--; } else//head处小,移动head的位置 { head++; } } } num[head]=tmp_cmp; //此时确认head==tail处正是这一个元素的真实位置,借此二分继续查找 if(start<=head-1) quick_sort(num,start,head-1); if(head+1<=end) quick_sort(num,head+1,end); return; }
215. 数组中的第K个最大元素
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class Solution { public: int deal(int donser[],int k,int num) { int up,down,out,sit,*lable; lable=new int[num]; for(int ii=0;ii<num;ii++) lable[ii]=0; while(1) { up=0;//找up down位置 down=num-1; for(int i=0;i<num;i++) { if(lable[i]==0) { up=i; break; } } for(int i=num-1;i>0;i--) { if(lable[i]==0) { down=i; break; } } out=donser[up];//要确定位置的值 sit=up;//坑 while(up<down) { if(sit==up) { if(out<=donser[down]) { down--; continue; } if(out>donser[down]) { donser[sit]=donser[down]; donser[down]=out; sit=down; up++; continue; } } else if(sit==down) { if(out>=donser[up]) { up++; continue; } if(out<donser[up]) { donser[sit]=donser[up]; donser[up]=out; sit=up; down--; continue; } } } lable[sit]=1; if(sit==num-k) break; } return donser[sit]; } int findKthLargest(vector<int>& nums, int k) { int i=nums.size(),*donser; donser=new int[i]; for(int c=0;c<i;c++) donser[c] = nums[c]; if(i==1) return donser[0]; return deal(donser,k,i); } };
快速实现代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<algorithm> #include<string.h> int qsor(const void *a,const void *b) { return *(int *)a-*(int *)b; } class Solution { public: int findKthLargest(vector<int>& nums, int k) { int i=nums.size(),*donser; donser=new int[i]; for(int c=0;c<i;c++) donser[c] = nums[c]; qsort(donser,i,sizeof(int),qsor); return donser[i-k]; } };
结构体的快排实现
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<algorithm> #include<string.h> #include<stdlib.h> struct donser { int i; int j; }; int qsor(const void* a,const void*b) { return (*(donser *)a).i-(*(donser *)b).i; } ...... struct donser my[1000]; ...... qsort(my,ii*2,sizeof(donser),qsor);
leetcode 面试题45. 把数组排成最小的数
自定义快排的比较规则
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<string.h> #include<stdlib.h> #include<algorithm> #include<iostream> #include<vector> #include<string> int cmp(const void * a,const void * b) { int len_a=0,len_b=0,tmp_a=*(int *)a,tmp_b=*(int *)b; if(tmp_a==0||tmp_b==0)//先判断防止出现0 return tmp_a-tmp_b; stack<char>aa,bb; //求出a和b的位数 每一位压栈 while(tmp_a!=0) { aa.push((tmp_a-(tmp_a/10)*10)+'0'); tmp_a/=10; len_a++; } while(tmp_b!=0) { bb.push((tmp_b-(tmp_b/10)*10)+'0'); tmp_b/=10; len_b++; } //把aa和bb比较,位数不足的用首数字补全 char A_start=aa.top(),B_start=bb.top(); while(aa.size()||bb.size()) { char A=A_start; if(aa.size()) { A=aa.top(); aa.pop(); } char B=B_start; if(bb.size()) { B=bb.top(); bb.pop(); } if(A==B) continue; return A-B; } //长度不同但是补齐以后相同,单独比较 long tp_a=*(int *)a; for(int i=0;i<len_b;i++) tp_a*=10; tp_a+=*(int *)b; long tp_b=*(int *)b; for(int i=0;i<len_a;i++) tp_b*=10; tp_b+=*(int *)a; return tp_a-tp_b; } class Solution { public: string minNumber(vector<int>& nums) { //int tmp[101]; for(int i=0;i<nums.size();i++) tmp[i]=nums[i]; qsort(tmp,nums.size(),sizeof(int),cmp);//自定义比较函数 string result=""; for(int i=0;i<nums.size();i++) { result+=to_string(tmp[i]); } return result; } };
想多了,根本不需要换成字符然后比较,直接补全成两串数字
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<string.h> #include<stdlib.h> #include<algorithm> #include<iostream> #include<vector> #include<string> int cmp(const void * a,const void * b) { int len_a=0,len_b=0,tmp_a=*(int *)a,tmp_b=*(int *)b; if(tmp_a==0||tmp_b==0)//先判断防止出现0 return tmp_a-tmp_b; //求出a和b的位数 每一位压栈 while(tmp_a!=0) { tmp_a/=10; len_a++; } while(tmp_b!=0) { tmp_b/=10; len_b++; } //长度不同但是补齐以后相同,单独比较 long tp_a=*(int *)a; for(int i=0;i<len_b;i++) tp_a*=10; tp_a+=*(int *)b; long tp_b=*(int *)b; for(int i=0;i<len_a;i++) tp_b*=10; tp_b+=*(int *)a; return tp_a-tp_b; } class Solution { public: string minNumber(vector<int>& nums) { int tmp[101]; for(int i=0;i<nums.size();i++) tmp[i]=nums[i]; qsort(tmp,nums.size(),sizeof(int),cmp);//自定义比较函数 string result=""; for(int i=0;i<nums.size();i++) { result+=to_string(tmp[i]); } return result; } };
优先队列和堆
优先队列有三个参数,其声明形式为:
priority_queue< type, container, function >
成员函数
假设type类型为int,则:
bool empty() const
返回值为true,说明队列为空;
int size() const
返回优先队列中元素的数量;
void pop()
删除队列顶部的元素,也即根节点
int top()
返回队列中的顶部元素,但不删除该元素;
void push(int arg)
将元素arg插入到队列之中;
大顶堆
//构造一个空的优先队列(此优先队列默认为大顶堆) priority_queue<int> big_heap;
//另一种构建大顶堆的方法 priority_queue<int,vector<int>,less<int> > big_heap2;
小顶堆
//构造一个空的优先队列,此优先队列是一个小顶堆 priority_queue<int,vector<int>,greater<int> > small_heap;
需要注意的是,如果使用less<int>
和greater<int>
,需要头文件:
#include <functional>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <stdio.h> #include <vector> #include <algorithm> #include <queue> using namespace std; class Solution { public: int findKthLargest(vector<int> &nums, int k) { int result = 0; int numsSize = int(nums.size()); if (numsSize == 0 || k > numsSize) { return 0; } priority_queue<int, vector<int>, greater<int>> store; //堆中维持k个最大数 for (int i = 0; i < numsSize; i++) { store.push(nums[i]); if (int(store.size()) > k) { store.pop(); } } result = store.top(); return result; } };