You are given two integer arrays nums1 and nums2 sorted in ascending order and an integer k.

Define a pair (u,v) which consists of one element from the first array and one element from the second array.

Find the k pairs (u1,v1),(u2,v2) ...(uk,vk) with the smallest sums.

Example 1:

Given nums1 = [1,7,11], nums2 = [2,4,6],  k = 3

Return: [1,2],[1,4],[1,6]

The first 3 pairs are returned from the sequence:
[1,2],[1,4],[1,6],[7,2],[7,4],[11,2],[7,6],[11,4],[11,6]

Example 2:

Given nums1 = [1,1,2], nums2 = [1,2,3],  k = 2

Return: [1,1],[1,1]

The first 2 pairs are returned from the sequence:
[1,1],[1,1],[1,2],[2,1],[1,2],[2,2],[1,3],[1,3],[2,3]

Example 3:

Given nums1 = [1,2], nums2 = [3],  k = 3 

Return: [1,3],[2,3]

All possible pairs are returned from the sequence:
[1,3],[2,3]

Credits:
Special thanks to @elmirap and @StefanPochmann for adding this problem and creating all test cases.

这道题给了我们两个数组,让我们从每个数组中任意取出一个数字来组成不同的数字对,返回前K个和最小的数字对。那么这道题有多种解法,我们首先来看brute force的解法,这种方法我们从0循环到数组的个数和k之间的较小值,这样做的好处是如果k远小于数组个数时,我们不需要计算所有的数字对,而是最多计算k*k个数字对,然后将其都保存在res里,这时候我们给res排序,用我们自定义的比较器,就是和的比较,然后把比k多出的数字对删掉即可,参见代码如下:

解法一:

class Solution {
public:
vector<pair<int, int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) {
vector<pair<int, int>> res;
for (int i = ; i < min((int)nums1.size(), k); ++i) {
for (int j = ; j < min((int)nums2.size(), k); ++j) {
res.push_back({nums1[i], nums2[j]});
}
}
sort(res.begin(), res.end(), [](pair<int, int> &a, pair<int, int> &b){return a.first + a.second < b.first + b.second;});
if (res.size() > k) res.erase(res.begin() + k, res.end());
return res;
}
};

我们也可以使用multimap来做,思路是我们将数组对之和作为key存入multimap中,利用其自动排序的机制,这样我们就可以省去sort的步骤,最后把前k个存入res中即可:

解法二:

class Solution {
public:
vector<pair<int, int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) {
vector<pair<int, int>> res;
multimap<int, pair<int, int>> m;
for (int i = ; i < min((int)nums1.size(), k); ++i) {
for (int j = ; j < min((int)nums2.size(), k); ++j) {
m.insert({nums1[i] + nums2[j], {nums1[i], nums2[j]}});
}
}
for (auto it = m.begin(); it != m.end(); ++it) {
res.push_back(it->second);
if (--k <= ) return res;
}
return res;
}
};

下面这种方式用了priority_queue,也需要我们自定义比较器,整体思路和上面的没有什么区别:

解法三:

class Solution {
public:
vector<pair<int, int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) {
vector<pair<int, int>> res;
priority_queue<pair<int, int>, vector<pair<int, int>>, cmp> q;
for (int i = ; i < min((int)nums1.size(), k); ++i) {
for (int j = ; j < min((int)nums2.size(), k); ++j) {
if (q.size() < k) {
q.push({nums1[i], nums2[j]});
} else if (nums1[i] + nums2[j] < q.top().first + q.top().second) {
q.push({nums1[i], nums2[j]}); q.pop();
}
}
}
while (!q.empty()) {
res.push_back(q.top()); q.pop();
}
return res;
}
struct cmp {
bool operator() (pair<int, int> &a, pair<int, int> &b) {
return a.first + a.second < b.first + b.second;
}
};
};

下面这种方法比较另类,我们遍历nums1数组,对于nums1数组中的每一个数字,我们并不需要遍历nums2中所有的数字,实际上,对于nums1中的数字,我们只需要记录nums2中下一个可能组成数字对的坐标,这里我们使用一个idx数组,其中idx[i]表示的数字是nums1[i]将从nums2数组上开始寻找的位置,因为 {nums1[i], nums2[i - 1]} 已经被加入到了结果res中,这种方法其实也是一种地毯式搜索,但是并不需要遍历完所有的组合,因为我们有idx数组来进行剪枝。我们suppose需要进行k次循环,但是题目中没有说我们一定能取出k对数字,而我们能取出的对儿数跟数组nums1和nums2的长度有关,最多能取出二者的长度之积的对儿数,所以我们取其跟k之间的较小值为循环次数。我们定义idx数组,长度为nums1的长度,初始化均为0。下面开始循环,在每次循环中,我们新建变量cur,记录从nums1中取数的位置,初始化为0,使用变量sum来记录一个当前最小的两数之和,初始化为正无穷。然后开始遍历数组nums1,更新sum的条件有两个,第一个是idx[i]上的数要小于nums2的长度,因为其是在nums2开始寻找的位置,当然不能越界,第二个条件的候选的两个数组 nums1[i] 和 nums2[idx[i]] 之和小于等于sum。同时满足这两个条件就可以更新sum了,同时更新cur为i,表示当前从nums1取出数字的位置。当遍历nums1的for循环结束后,此时cur的位置就是要从nums1取出的数字的位置,根据idx[cur]从nums2中取出对应的数组,形成数对儿存入结果res中,然后idx[cur]自增1,因为当前位置的数字已经用过了,下次遍历直接从后面一个数字开始吧,这是本解法的设计精髓所在,一定要弄清楚idx数组的意义,参见代码如下:

解法四:

class Solution {
public:
vector<pair<int, int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) {
vector<pair<int, int>> res;
int size = min(k, int(nums1.size() * nums2.size()));
vector<int> idx(nums1.size(), );
for (int t = ; t < size; ++t) {
int cur = , sum = INT_MAX;
for (int i = ; i < nums1.size(); ++i) {
if (idx[i] < nums2.size() && sum >= nums1[i] + nums2[idx[i]]) {
cur = i;
sum = nums1[i] + nums2[idx[i]];
}
}
res.push_back({nums1[cur], nums2[idx[cur]]});
++idx[cur];
}
return res;
}
};

参考资料:

https://discuss.leetcode.com/topic/50429/c-solution

https://discuss.leetcode.com/topic/50459/c-idea-of-using-multimap

https://discuss.leetcode.com/topic/50422/naive-accepted-solution-c

https://discuss.leetcode.com/topic/50421/c-priority_queue-solution

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Find K Pairs with Smallest Sums 找和最小的K对数字的更多相关文章

  1. [LeetCode] 373. Find K Pairs with Smallest Sums 找和最小的K对数字

    You are given two integer arrays nums1 and nums2 sorted in ascending order and an integer k. Define ...

  2. 373 Find K Pairs with Smallest Sums 查找和最小的K对数字

    给定两个以升序排列的整形数组 nums1 和 nums2, 以及一个整数 k.定义一对值 (u,v),其中第一个元素来自 nums1,第二个元素来自 nums2.找到和最小的 k 对数字 (u1,v1 ...

  3. 373. Find K Pairs with Smallest Sums 找出求和和最小的k组数

    [抄题]: You are given two integer arrays nums1 and nums2 sorted in ascending order and an integer k. D ...

  4. 【LeetCode】373. Find K Pairs with Smallest Sums 解题报告(Python)

    [LeetCode]373. Find K Pairs with Smallest Sums 解题报告(Python) 标签: LeetCode 题目地址:https://leetcode.com/p ...

  5. 373. Find K Pairs with Smallest Sums

    You are given two integer arrays nums1 and nums2 sorted in ascending order and an integer k. 给你两个数组n ...

  6. 373. Find K Pairs with Smallest Sums (java,优先队列)

    题目: You are given two integer arrays nums1 and nums2 sorted in ascending order and an integer k. Def ...

  7. #Leetcode# 373. Find K Pairs with Smallest Sums

    https://leetcode.com/problems/find-k-pairs-with-smallest-sums/ You are given two integer arrays nums ...

  8. Find K Pairs with Smallest Sums -- LeetCode

    You are given two integer arrays nums1 and nums2 sorted in ascending order and an integer k. Define ...

  9. 【leetcode】Find K Pairs with Smallest Sums

    You are given two integer arrays nums1 and nums2 sorted in ascending order and an integer k. Define ...

随机推荐

  1. javascript学习笔记一

    今天看的javascript 应用开发实践指南 看了js库 jquery ,明确了要深入学习jquery的想法. 对于javascript原生态的ajax写法(兼容性只需考虑ie6),封装为函数: f ...

  2. 微信支付:H5吊起支付API,不显示“确认支付、输入密码”界面

    使用公众号进行支付,官方开发帮助文档: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1 其业务流程如下: 按照业务流程进行开发 ...

  3. 在 C# 中定义一个真正只读的 List

    C# 中的 readonly 关键字表示类中的字段只允许在定义时候或者构造方法中初始化.普通类型的数据完全可以达到预期的效果,但是在对象或者列表中,要想达到只读的效果,只用一个 readonly 关键 ...

  4. 来,一起让我们越来越懒,面向CSS、JS未来编程。(9.28已更新)

    2016.10.29更新 本文存在大量的错误,仅供参考. 不知不觉在前端领域马上一个年头就要过去了,然而再看看自己的代码,果然够烂,那么为什么代码一直没有用面向对象的思维去写CSS呢?首先有两点:一点 ...

  5. 获取asp.net服务器控件的客户端ID和Name

    前几天在做项目的时候,遇到一个问题,想查看Asp.net中服务器控件在客户端显示的name属性.起初,感觉不是很难找,但就是找不到,几经周折,终于发现了: string btnClientName = ...

  6. Delphi_03_Delphi_Object_Pascal_基本语法_01

    这次是一个基本语法的第一部分,包括变量.变量初始化.常量.运算符.字符串等内容. { 本程序演示 Delphi Pascal 的基本语法 1.变量及变量的初始化 2.常量 3.运算符 3. 4. } ...

  7. CentOS6.8 修改主机名(1)

    1.临时修改主机名   显示主机名:spark@master:~$ hostnamemaster修改主机名:spark@master:~$ sudo hostname hadoopspark@mast ...

  8. Hibernate4.2.4入门(一)——环境搭建和简单例子

    一.前言 发下牢骚,这段时间要做项目,又要学框架,搞得都没时间写笔记,但是觉得这知识学过还是要记录下.进入主题了 1.1.Hibernate简介 什么是Hibernate?Hibernate有什么用? ...

  9. Canvas的width,height 和 样式中Canvas的width,height

    控制Canvas的大小,有两种方式: 1:直接设置Canvas标签上的书width,height属性值; 2:通过Css设置Canvas的width,height; 这两种方式,区别是很大的. 1:C ...

  10. iOS 网络流量统计

    在开发中,有时候需要获取流量统计信息.研究发现:通过函数getifaddrs来得到系统网络接口的信息,网络接口的信息,包含在if_data字段中, 有很多信息, 但我现在只关心ifi_ibytes,  ...