• 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;
        }
    };
  • 相关阅读:
    mysql修改数据表名
    HDU 5742 It's All In The Mind (贪心)
    HDU 5752 Sqrt Bo (数论)
    HDU 5753 Permutation Bo (推导 or 打表找规律)
    HDU 5762 Teacher Bo (暴力)
    HDU 5754 Life Winner Bo (博弈)
    CodeForces 455C Civilization (并查集+树的直径)
    CodeForces 455B A Lot of Games (博弈论)
    CodeForces 455A Boredom (DP)
    HDU 4861 Couple doubi (数论 or 打表找规律)
  • 原文地址:https://www.cnblogs.com/Babylon/p/15634639.html
Copyright © 2020-2023  润新知