Description

给定两个已排序的数组nums1[]nums2[],和一个常数k。设元组p(u,v)为从nums1[]拿取u,且从nums2[]拿取v

返回k个元组p(ui,vj)使得它们的和最小

Constraints

  • nums1[]nums2[]长度不超过105
  • nums1[i]nums2[i]都在int范围内
  • k不超过104

Solution

假设你拿了uivj,那么可以确定:

  • ui+vjui+vj+1
  • ui+vjui+1+vj

但是你不知道ui+vj对比ui+1+v0或者u0+vj+1的大小关系

所以初始化就是把所有p(u0,vj)p(ui,v0)都放到堆里,拿走一个最优解后各下标偏移1位

注意不要重复放取,因此加上一个vis

Code

class Solution {
public:
    vector<vector<int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) {
        using Tup = tuple<int, int>;
        auto cmp = [&](auto &a, auto &b) {
            auto &[a1, a2] = a;
            auto &[b1, b2] = b;
            return nums1[a1] + nums2[a2] > nums1[b1] + nums2[b2];
        };
        priority_queue<Tup, vector<Tup>, decltype(cmp)> pq(cmp);
        unordered_map<size_t, unordered_map<size_t, bool>> vis;
        for(size_t i = 0; i < nums1.size(); ++i) {
            vis[i][0] = true;
            pq.emplace(make_tuple(i, 0));
        }
        for(size_t j = 1; j < nums2.size(); ++j) {
            vis[0][j] = true;
            pq.emplace(make_tuple(0, j));
        }
        vector<vector<int>> ans;
        while(ans.size() < k && !pq.empty()) {
            auto [i, j] = pq.top();
            pq.pop();
            vector<int> best {nums1[i], nums2[j]};
            ans.emplace_back(move(best));
            const int d[] = {1, 0};
            for(auto t = 0; t < 2; ++t) {
                auto ni = i + d[t];
                auto nj = j + d[t^1];
                if(ni >= nums1.size() || nj >= nums2.size()) continue;
                if(vis[ni][nj]) continue;
                vis[ni][nj] = true;
                pq.emplace(make_tuple(ni, nj));
            }
        }
        return ans;
    }
};

LeetCode-373 Find K Pairs with Smallest Sums