leetcode373

1.微扰理论二分法

leetcode373

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;
    }
};

 

 

上一篇:问题 E: 大整数排序


下一篇:【大数篇】加法--减法篇