求两个有序数组两两相加的值最小的K个数
2016-08-06 13:29
197 查看
题目描述:
有两个大小分别是lenA和lenB的数组A,B,它们元素的按非递减有序排列,找出这样的k个最小的(ai + bj) ,其中 0<= i < lenA,0<= j < lenB,要求算法的时间复杂度和空间复杂度尽量低。
例如对于:
A = 1,2,3,4
B = 2,3,4,5
ai+bj的所有组合有4*4 = 16个,如下图:
b\a 1 2 3 4
2 3 4 5 6
3 4 5 6 7
4 5 6 7 8
5 6 7 8 9
依次排序为:3,4,4,5, 5,5,6,6, 6,6,7,7, 7,8,8,9 (共16个)
解题思路:
最小堆方法实现的代码,其思路如下:
首先把a0+b0的结果放入堆中,此时堆中只有一个元素,自然满足最小堆条件,然后开始出堆的操作,从堆里面取出根节点(也就是最小的值),例如是a[i]+b[j],则需要像最小堆中压入a[i+1]b[j] 和 a[i]+b[j+1],当然,要保证下标不越界,如果下标越界了则忽略,另外要保证已经压入过堆中的组合(即使已经从堆中被取出了的)不再被压入堆中。不段进行出堆、入堆的操作,重复K次,就得到了K个最小的组合值。
堆的最大深度为logK,所以时间复杂度为K*logK数量级。
实现代码如下:
有两个大小分别是lenA和lenB的数组A,B,它们元素的按非递减有序排列,找出这样的k个最小的(ai + bj) ,其中 0<= i < lenA,0<= j < lenB,要求算法的时间复杂度和空间复杂度尽量低。
例如对于:
A = 1,2,3,4
B = 2,3,4,5
ai+bj的所有组合有4*4 = 16个,如下图:
b\a 1 2 3 4
2 3 4 5 6
3 4 5 6 7
4 5 6 7 8
5 6 7 8 9
依次排序为:3,4,4,5, 5,5,6,6, 6,6,7,7, 7,8,8,9 (共16个)
解题思路:
最小堆方法实现的代码,其思路如下:
首先把a0+b0的结果放入堆中,此时堆中只有一个元素,自然满足最小堆条件,然后开始出堆的操作,从堆里面取出根节点(也就是最小的值),例如是a[i]+b[j],则需要像最小堆中压入a[i+1]b[j] 和 a[i]+b[j+1],当然,要保证下标不越界,如果下标越界了则忽略,另外要保证已经压入过堆中的组合(即使已经从堆中被取出了的)不再被压入堆中。不段进行出堆、入堆的操作,重复K次,就得到了K个最小的组合值。
堆的最大深度为logK,所以时间复杂度为K*logK数量级。
实现代码如下:
#include <iostream> #include <vector> #include <algorithm> #include <map> using namespace std; struct Node{ int posA; int posB; int sum; Node(){} Node(int a, int b, int s) :posA(a), posB(b), sum(s){} }; class Solution{ public: static bool cmp(const Node& node1, const Node& node2) { return node1.sum > node2.sum; } vector<int> topKOfTwoSortedArray(const vector<int>& A, const vector<int>& B, int k) { vector<int> ans; if ((A.size() == 0 && B.size() == 0) || k<=0) return ans; int nA = A.size(); int nB = B.size(); if (k > nA*nB) k = nA*nB; map<pair<int,int>, bool> stats; vector<Node> heapAux; heapAux.push_back(Node(0,0,A[0]+B[0])); stats[make_pair(0,0)] = true; make_heap(heapAux.begin(), heapAux.end(), cmp); while (k>0){ pop_heap(heapAux.begin(), heapAux.end(), cmp); Node tmp = heapAux.back(); heapAux.pop_back(); ans.push_back(tmp.sum); --k; int idxA = tmp.posA; int idxB = tmp.posB; if (idxA + 1 < nA && !stats[make_pair(idxA + 1, idxB)]){ stats[make_pair(idxA + 1, idxB)] = true; heapAux.push_back(Node(idxA + 1, idxB, A[idxA + 1] + B[idxB])); push_heap(heapAux.begin(), heapAux.end(), cmp); } if (idxB + 1 < nB && !stats[make_pair(idxA, idxB + 1)]){ stats[make_pair(idxA, idxB + 1)] = true; heapAux.push_back(Node(idxA, idxB + 1, A[idxA] + B[idxB + 1])); push_heap(heapAux.begin(), heapAux.end(), cmp); } } return ans; } }; int main() { vector<int> A = {1,2,3,4}; vector<int> B = {2,3,4,5}; int k = 12; Solution sln; vector<int> ans = sln.topKOfTwoSortedArray(A, B, k); for (int i = 0; i < k; ++i){ cout << ans[i] << " "; } cout << endl; return 0; }
相关文章推荐
- 算法-求两个有序数组两两相加的值最小的K个数
- 【面试题】求两个有序数组两两相加的值最小的K个数
- 求两个有序数组两两相加的值最小的K个数
- 算法-求两个有序数组两两相加的值最小的K个数
- 求两个有序数组中,各个元素的c差值最小
- 有一个整数数组,请求出两两之差绝对值最小的值,记住,只要得出最小值即可,不需要求出是哪两个数。 (微软面试题)
- 算法面试题——两个有序数组,将一个数组放入另一个空间很大的数组,要求合并之后依然有序,时间复杂度要求最小,不使用额外的数组。
- 两个有序数组元素之积、和的最小K个值
- 两个有序数组相加和的topK问题
- 两个有序数组元素之和的最小K个值
- 其他题目---两个有序数组间相加和的TopK问题
- 两个数组分别取出一个来相加,找出和最小的k个
- 一道面试题:有一个整数数组,请求出两两之差绝对值最小的值,记住,只要得出最小值即可,不需要求出是哪两个数。
- 有一个整数数组,请求出两两之差绝对值最小的值,记住,只要得出最小值即可,不需要求出是哪两个数。
- 有一个整数数组,请求出两两之差绝对值最小的值,记住,只要得出最小值即可,不需要求出是哪两个数。
- 有一个整数数组,请求出两两之差最小的值,记住,只要得出最小值即可,不需要求出是哪两个数。
- 两有序数组两两之和的最小k个值, 最小堆解法之完整版
- 每日一题(95) - 两个有序数组元素之积、和的最小K个值
- 有一个整数数组,请求出两两之差绝对值最小的值, 记住,只要得出最小值即可,不需要求出是哪两个数。
- 有一个整数数组,请求出两两之差绝对值最小的值,记住,只要得出最小值即可,不需要求出是哪两个数。