leetcode373

 

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;
    }
};
原文地址:https://www.cnblogs.com/Babylon/p/15634639.html