4.最终版在三基础上将vector优先队列替换为pair<int,pair<int,int>>
class Solution { struct cmp { bool operator() (const pair<int, pair<int, int> >& a, const pair<int, pair<int, int> >& b) { return a.first + a.second.first > b.first + b.second.first; } }; public: vector<vector<int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) { //用一个优先队列存下nums1全部值和nums2从0开始的值,取出一个就将那个位置的值前移动一位直到满足k个或者优先队列清空 //使用nums1和nums2中较小的做优先队列,这样长度相对小点 vector<vector<int>> ret; //vector长度为3,0存nums1值,1存nums2值,3存正选定的滑动数组的下标 priority_queue <pair<int,pair<int,int> >,vector<pair<int, pair<int, int> > >, cmp > q; int len1=nums1.size(),len2=nums2.size(); //cout<<1<<endl; //二分法减枝 long long left=long(nums1[0])+long(nums2[0]), right=((long(nums1[len1-1])-long(nums1[0]))/len1+(long(nums2[len2-1])-long(nums2[0]))/len2+(long(nums1[0])+long(nums2[0]))/k)/2*k, mid=0; int cnt=0,j=0; //k超过最大范围直接输出 if(k/len1>=len2){ for(int i=0;i<len1;i++){ j=0; while(j<len2){ pair<int, pair<int, int> > vp(nums1[i], pair<int, int>(nums2[j] , 0)); q.push(vp); j++; } } while(k&&!q.empty()){ k--; ret.push_back({q.top().first,q.top().second.first}); q.pop(); } return ret; } if(left>=right){ left=right; } int last=0; while(left <= right){ mid=left + (right-left)/2; cnt=0; for(int i=0;i<len1;i++){ j=0; while(j<len2&&(nums1[i]+nums2[j])<=mid)j++; cnt+=j; if(j==0){ break; } } //cout<<cnt<<endl; if(cnt==k||(cnt>k&&last<k)){ break; } if(left==right&&last<=k){ right+=right/2+1; } last=cnt; //二分搜索操作 if (cnt < k) left = mid+1; else right = mid; //cout<<"last:"<<last<<"left:"<<left<<"right:"<<right<<"mid:"<<mid<<endl; } ////////////////////////////// //cout<<left<<":"<<right<<endl; if(len1<len2){ //cout<<"A"<<endl; for(int i=0;i<len1;i++){ //cout<<2<<endl; if(nums1[i]+nums2[0]<=mid){ pair<int, pair<int, int> > vp(nums1[i], pair<int, int>(nums2[0] , 0)); q.push(vp); } } while(k--&&!q.empty()){ //cout<<3<<endl; pair<int, pair<int, int> > vp=q.top(); q.pop(); ret.push_back({vp.first,vp.second.first}); vp.second.second++; if(vp.second.second<len2){ vp.second.first=nums2[vp.second.second]; if(vp.first+vp.second.first<=mid){ q.push(vp); } } } }else{ //逆转时为满足cmp函数需交换vp[1],vp[0]的位置 //cout<<"B"<<endl; for(int i=0;i<len2;i++){ //cout<<4<<endl; if(nums1[0]+nums2[i]<=mid){ pair<int, pair<int, int> > vp(nums1[0], pair<int, int>(nums2[i] , 0)); q.push(vp); } } while(k--&&!q.empty()){ //cout<<5<<endl; pair<int, pair<int, int> > vp=q.top(); q.pop(); ret.push_back({vp.first,vp.second.first}); vp.second.second++; if(vp.second.second<len1){ vp.first=nums1[vp.second.second]; if(vp.first+vp.second.first<=mid){ q.push(vp); } } } } return ret; } };
1.微扰理论二分法
class Solution { struct cmp { bool operator() (const vector<int> &a,const vector<int> &b) { if(a[0]+a[1] == b[0]+b[1]){ return a[1] > b[1]; }else{ return a[0]+a[1] > b[0]+b[1]; } } }; public: vector<vector<int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) { vector<vector<int>> ret; priority_queue <vector<int>,vector<vector<int>>,cmp > q; int len1=nums1.size(),len2=nums2.size(); long long left=long(nums1[0])+long(nums2[0]), right=((long(nums1[len1-1])-long(nums1[0]))/len1+(long(nums2[len2-1])-long(nums2[0]))/len2+(long(nums1[0])+long(nums2[0]))/k)/2*k, mid=0; int cnt=0,j=0; vector<int> vp; //cout<<len1<<":"<<len2<<endl; //k超过最大范围直接输出 if(k>=len1*len2){ for(int i=0;i<len1;i++){ j=0; while(j<len2){ vp={nums1[i], nums2[j]}; q.push(vp); j++; } } while(k&&!q.empty()){ k--; ret.push_back(q.top()); q.pop(); } return ret; } if(left>=right){ left=right; } int last=0; //cout<<left<<":"<<right<<endl; while(left <= right){ mid=left + (right-left)/2; cnt=0; for(int i=0;i<len1;i++){ j=0; while(j<len2&&(nums1[i]+nums2[j])<=mid)j++; cnt+=j; if(j==0){ break; } } //cout<<cnt<<endl; if(cnt==k||(cnt>k&&last<k)){ for(int i=0;i<len1;i++){ j=0; while(j<len2&&(nums1[i]+nums2[j])<=mid){ vp={nums1[i], nums2[j]}; q.push(vp); //q.emplace(nums1[i], nums2[j]); //cnt++; j++; } if(j==0){ break; } } while(k&&!q.empty()){ k--; ret.push_back(q.top()); q.pop(); } return ret; } if(left==right&&last<=k){ right+=right/2+1; } last=cnt; //二分搜索操作 if (cnt < k) left = mid+1; else right = mid; //cout<<"last:"<<last<<"left:"<<left<<"right:"<<right<<"mid:"<<mid<<endl; } return ret; } };
2.优先队列按其中一个数组为基础滑动
class Solution { struct cmp { bool operator() (const vector<int> &a,const vector<int> &b) { if(a[0]+a[1] == b[0]+b[1]){ return a[1] > b[1]; }else{ return a[0]+a[1] > b[0]+b[1]; } } }; public: vector<vector<int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) { //用一个优先队列存下nums1全部值和nums2从0开始的值,取出一个就将那个位置的值前移动一位直到满足k个或者优先队列清空 //使用nums1和nums2中较小的做优先队列,这样长度相对小点 vector<vector<int>> ret; //vector长度为3,0存nums1值,1存nums2值,3存正选定的滑动数组的下标 priority_queue <vector<int>,vector<vector<int>>,cmp > q; int len1=nums1.size(),len2=nums2.size(); vector<int> vp; //cout<<1<<endl; if(len1<len2){ //cout<<"A"<<endl; for(int i=0;i<len1;i++){ //cout<<2<<endl; vp={nums1[i],nums2[0],0}; q.push(vp); } while(k--&&!q.empty()){ //cout<<3<<endl; vp=q.top(); q.pop(); ret.push_back({vp[0],vp[1]}); vp[2]++; if(vp[2]<len2){ vp[1]=nums2[vp[2]]; q.push(vp); } } }else{ //逆转时为满足cmp函数需交换vp[1],vp[0]的位置 //cout<<"B"<<endl; for(int i=0;i<len2;i++){ //cout<<4<<endl; vp={nums1[0],nums2[i],0}; q.push(vp); } while(k--&&!q.empty()){ //cout<<5<<endl; vp=q.top(); q.pop(); ret.push_back({vp[0],vp[1]}); vp[2]++; if(vp[2]<len1){ vp[0]=nums1[vp[2]]; q.push(vp); } } } return ret; } };
3.解法1和2综合
class Solution { struct cmp { bool operator() (const vector<int> &a,const vector<int> &b) { if(a[0]+a[1] == b[0]+b[1]){ return a[1] > b[1]; }else{ return a[0]+a[1] > b[0]+b[1]; } } }; public: vector<vector<int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) { //用一个优先队列存下nums1全部值和nums2从0开始的值,取出一个就将那个位置的值前移动一位直到满足k个或者优先队列清空 //使用nums1和nums2中较小的做优先队列,这样长度相对小点 vector<vector<int>> ret; //vector长度为3,0存nums1值,1存nums2值,3存正选定的滑动数组的下标 priority_queue <vector<int>,vector<vector<int>>,cmp > q; int len1=nums1.size(),len2=nums2.size(); vector<int> vp; //cout<<1<<endl; //二分法减枝 long long left=long(nums1[0])+long(nums2[0]), right=((long(nums1[len1-1])-long(nums1[0]))/len1+(long(nums2[len2-1])-long(nums2[0]))/len2+(long(nums1[0])+long(nums2[0]))/k)/2*k, mid=0; int cnt=0,j=0; //k超过最大范围直接输出 if(k/len1>=len2){ for(int i=0;i<len1;i++){ j=0; while(j<len2){ vp={nums1[i], nums2[j]}; q.push(vp); j++; } } while(k&&!q.empty()){ k--; ret.push_back(q.top()); q.pop(); } return ret; } if(left>=right){ left=right; } int last=0; while(left <= right){ mid=left + (right-left)/2; cnt=0; for(int i=0;i<len1;i++){ j=0; while(j<len2&&(nums1[i]+nums2[j])<=mid)j++; cnt+=j; if(j==0){ break; } } //cout<<cnt<<endl; if(cnt==k||(cnt>k&&last<k)){ break; } if(left==right&&last<=k){ right+=right/2+1; } last=cnt; //二分搜索操作 if (cnt < k) left = mid+1; else right = mid; //cout<<"last:"<<last<<"left:"<<left<<"right:"<<right<<"mid:"<<mid<<endl; } ////////////////////////////// //cout<<left<<":"<<right<<endl; if(len1<len2){ //cout<<"A"<<endl; for(int i=0;i<len1;i++){ //cout<<2<<endl; if(nums1[i]+nums2[0]<=mid){ vp={nums1[i],nums2[0],0}; q.push(vp); } } while(k--&&!q.empty()){ //cout<<3<<endl; vp=q.top(); q.pop(); ret.push_back({vp[0],vp[1]}); vp[2]++; if(vp[2]<len2){ vp[1]=nums2[vp[2]]; if(vp[0]+vp[1]<=mid){ q.push(vp); } } } }else{ //逆转时为满足cmp函数需交换vp[1],vp[0]的位置 //cout<<"B"<<endl; for(int i=0;i<len2;i++){ //cout<<4<<endl; if(nums1[0]+nums2[i]<=mid){ vp={nums1[0],nums2[i],0}; q.push(vp); } } while(k--&&!q.empty()){ //cout<<5<<endl; vp=q.top(); q.pop(); ret.push_back({vp[0],vp[1]}); vp[2]++; if(vp[2]<len1){ vp[0]=nums1[vp[2]]; if(vp[0]+vp[1]<=mid){ q.push(vp); } } } } return ret; } };