[LeetCode] 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 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对数字的更多相关文章
- [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 ...
- 373 Find K Pairs with Smallest Sums 查找和最小的K对数字
给定两个以升序排列的整形数组 nums1 和 nums2, 以及一个整数 k.定义一对值 (u,v),其中第一个元素来自 nums1,第二个元素来自 nums2.找到和最小的 k 对数字 (u1,v1 ...
- 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 ...
- 【LeetCode】373. Find K Pairs with Smallest Sums 解题报告(Python)
[LeetCode]373. Find K Pairs with Smallest Sums 解题报告(Python) 标签: LeetCode 题目地址:https://leetcode.com/p ...
- 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 ...
- 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 ...
- #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 ...
- 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 ...
- 【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 ...
随机推荐
- C#6新特性,让你的代码更干净
前言 前几天看一个朋友的博客时,看他用到了C#6的特性,而6出来这么长时间还没有正儿八经看过它,今儿专门看了下新特性,说白了也不过是语法糖而已.但是用起来确实能让你的代码更加干净些.Let's try ...
- 4.JAVA之GUI编程事件监听机制
事件监听机制的特点: 1.事件源 2.事件 3.监听器 4.事件处理 事件源:就是awt包或者swing包中的那些图形用户界面组件.(如:按钮) 事件:每一个事件源都有自己特点有的对应事件和共性事件. ...
- JavaScript实现图片轮播组件
效果: 自动循环播放图片,下方有按钮可以切换到对应图片. 添加一个动画来实现图片切换. 鼠标停在图片上时,轮播停止,出现左右两个箭头,点击可以切换图片. 鼠标移开图片区域时,从当前位置继续轮播. 提供 ...
- 前端打包构建工具gulp快速入门
因为之前一直有人给我推荐gulp,说他这里好哪里好的.实际上对我来说够用就行.grunt熟悉以后实际上他的配置也不难,说到效率的话确实是个问题,尤其项目大了以后,目前位置遇到的项目都还可以忍受.不过不 ...
- ASP.NET Core 整合Autofac和Castle实现自动AOP拦截
前言: 除了ASP.NETCore自带的IOC容器外,我们还可以使用其他成熟的DI框架,如Autofac,StructureMap等(笔者只用过Unity,Ninject和Castle). 1.ASP ...
- Intellij Idea 15 下新建 Hibernate 项目以及如何添加配置
1.说明:Idea 下,项目对应于 Eclipse 下的 workspace,Module 对应于 Eclipse 下的项目.Idea 下,新添加的项目既可以单独作为一个 Project,也可以作为一 ...
- 解决微信授权回调页面域名只能设置一个的问题 [php]
最终的解决方案是:https://github.com/liuyunzhuge/php_weixin_proxy,详细的介绍请往下阅读. 在做项目集成微信登录以及微信支付的时候,都需要进行用户授权.这 ...
- 用python实现最长公共子序列算法(找到所有最长公共子串)
软件安全的一个小实验,正好复习一下LCS的写法. 实现LCS的算法和算法导论上的方式基本一致,都是先建好两个表,一个存储在(i,j)处当前最长公共子序列长度,另一个存储在(i,j)处的回溯方向. 相对 ...
- React Native环境搭建以及几个基础控件的使用
之前写了几篇博客,但是没有从最基础的开始写,现在想了想感觉不太合适,所以现在把基础的一些东西给补上,也算是我从零开始学习RN的经验吧! 一.环境搭建 首先声明一下,本人现在用的编辑器是SublimeT ...
- C#多态“说来也说”——逻辑层BLL中的多态使用
本文版权归博客园和作者吴双本人共同所有.欢迎转载,转载和爬虫请注明原文地址 http://www.cnblogs.com/tdws/p/5861842.html 昨天晚上,有个朋友说学了好久,依然没搞 ...