• 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;
        }
    };
  • 相关阅读:
    [leetcode]Longest Common Prefix
    [leetcode]Container With Most Water
    [leetcode]Regular Expression Matching
    [leetcode]Palindrome Number
    [leetcode]String to Integer (atoi)
    [leetcode]Reverse Integer
    [leetcode]ZigZag Conversion
    [leetcode]Longest Palindromic Substring
    [leetcode]Add Two Numbers
    poj 1228 Grandpa's Estate
  • 原文地址:https://www.cnblogs.com/Babylon/p/15634639.html
Copyright © 2020-2023  润新知