---
# System prepended metadata

title: 373. Find K Pairs with Smallest Sums
tags: [leetcode]

---

---
title: 373. Find K Pairs with Smallest Sums
tags: leetcode
disqus: foodtoothshackmd
---

https://leetcode.com/problems/find-k-pairs-with-smallest-sums/

## Idea
We can sort all of them in a priority_queue and pick.

### Smart one
由于全量的排序操作，元素移位操作等损耗很大。针对这$m \times n$对数的排列（这个矩阵），可以直接考虑出方法找出当前候选值中的小值，然后往复到结束条件。

## Code
### Straight forward
```cpp
class Solution {
 public:
  vector<vector<int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2,
                                     int k) {
    auto cmp = [](const std::vector<int>& left, const std::vector<int>& right) {
      return left.front() + left.back() < right.front() + right.back();
    };
    std::priority_queue<std::vector<int>, std::vector<std::vector<int>>,
                        decltype(cmp)>
        pq(cmp);
    for (int i{}; i < nums1.size(); ++i) {
      for (int j{}; j < nums2.size(); ++j) {
        pq.emplace((std::initializer_list<int>){nums1[i], nums2[j]});
        if (pq.size() > k) pq.pop();
      }
    }
    std::vector<std::vector<int>> result;
    while (!pq.empty()) {
      result.push_back(pq.top());
      pq.pop();
    }
    return result;
  }
};
```

### Smart one
```cpp
class Solution {
 public:
  vector<vector<int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2,
                                     int k) {
    int nums1_size = nums1.size();
    int nums2_size = nums2.size();

    std::vector<std::vector<int>> result{};
    if (nums1_size == 0 || nums2_size == 0) return result;

    // Comparision func for cands(extract index from tuple and compare sum)
    auto cmp = [&nums1, &nums2](auto left, auto right) {
      return nums1[std::get<0>(left)] + nums2[std::get<1>(left)] >
             nums1[std::get<0>(right)] + nums2[std::get<1>(right)];
    };
    std::priority_queue<std::tuple<int, int>, std::vector<std::tuple<int, int>>,
                        decltype(cmp)>
        cands(cmp);

    // Checkers are used to check whether there is smaller one already in cands
    std::vector<bool> x_checker(nums1_size, false);
    std::vector<bool> y_checker(nums2_size, false);

    int x{}, y{};
    while (true) {
      if (k == 0 || (x + 1 == nums1_size && y + 1 == nums2_size)) {
        return result;
      }
      // Handle first-one condition
      if (cands.empty()) {
        cands.emplace(x, y);
        x_checker[x] = true;
        y_checker[y] = true;
      }

      // Get current smallest sum one
      std::tie(x, y) = cands.top();
      cands.pop();
      x_checker[x] = false;
      y_checker[y] = false;
      result.emplace_back(std::initializer_list<int>{nums1[x], nums2[y]});
      --k;

      // Push new candidates according to popped one
      if (x + 1 < nums1_size && !x_checker[x + 1]) {
        cands.emplace(x + 1, y);
        x_checker[x + 1] = true;
        y_checker[y] = true;
      }
      if (y + 1 < nums2_size && !y_checker[y + 1]) {
        cands.emplace(x, y + 1);
        x_checker[x] = true;
        y_checker[y + 1] = true;
      }
    }
  }
};
```