1、两个有序数组的中位数
2、找到两个数组中最小的k对最小和
天上浮云如白衣,斯须改变如苍狗。——杜甫《何叹》
There are two sorted arrays nums1 and nums2 of size m and n respectively.
Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).
Example 1:
nums1 = [1, 3]
nums2 = [2]
The median is 2.0
Example 2:
nums1 = [1, 2]
nums2 = [3, 4]
The median is (2 + 3)/2 = 2.5
tag:数组|二分|分治
题意:先给定两个数组,求它们的中位数,复杂度O(log (m+n)).
思路:
1、找中位数就是在两个数组中各自找到一个i、j元素作为分割线,分割线需要满足三个方程:
i+j=(nums1.size()+nums2.size()+1)/2 —> 二分去搜索i.j=(nums1.size()+nums2.size()+1)/2-i
nums1[i-1]<=nums2[j] (前提i-1和j不越界)
nums2[j-1]<=nums1[i] (前提j-1和i不越界)
当找到满足条件的i,j时候就返回,
否则如果nums1[i-1]
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int len1 = nums1.size(),len2 = nums2.size();
if(len1>len2) return findMedianSortedArrays(nums2,nums1);
int halfLen = (len1+len2+1)/2;
int iLeft = 0,iRight = len1;
double maxLeft = INT_MIN,minRight = INT_MAX;
while(iLeft<=iRight)
{
int i = iLeft+(iRight-iLeft)/2;
int j = halfLen-i;
if(j>0 && i1])
iLeft = i+1;
else if(i>0 && j1])
iRight = i-1;
else
{
if(i==0)
maxLeft = nums2[j-1];
else if(j==0)
maxLeft = nums1[i-1];
else
maxLeft = max(nums1[i-1],nums2[j-1]);
if((len1+len2)%2==1)
return maxLeft;
else if(i==len1)
minRight = nums2[j];
else if (j==len2)
minRight = nums1[i];
else
minRight = min(nums1[i],nums2[j]);
return (maxLeft+minRight)/2;
}
}
return -1;
}
};
结果:29ms
2、一样的思想,转换成找两个数组中的第K大数。
这里偶数个数的情况下要调用两次函数,可以改成加如一个标志位来做。
class Solution {
public:
double findLargestK(const vector<int>&nums1,const vector<int>& nums2,int len1,int len2,int k)
{
int iLeft = 0,iRight = len1;
double res =0;
while(iLeft<=iRight)
{
int i = iLeft+(iRight-iLeft)/2;
int j = k-i;
if(j>len2 ||j>0 && i1])
iLeft = i+1;
else if(i>len1 || i>0 && j1])
iRight = i-1;
else
{
if(i==0)
res = nums2[j-1];
else if(j==0)
res = nums1[i-1];
else
res = max(nums1[i-1],nums2[j-1]);
return res;
}
}
return -1;
}
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int len1 = nums1.size(),len2 = nums2.size();
if(len1>len2) return findMedianSortedArrays(nums2,nums1);
int totalLen = len1+len2;
if(totalLen%2==1) return findLargestK(nums1,nums2,len1,len2,totalLen/2+1);
else return (findLargestK(nums1,nums2,len1,len2,totalLen/2)+ findLargestK(nums1,nums2,len1,len2,totalLen/2+1))/2;
}
};
结果:62ms
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]
tag:堆
题意:找到两个数组中最小的k对最小和
思路:
1、建立一个最小堆,这样每次堆顶都是我们需要找的一对数,但是现在不是对一个数字进行排序,而是对一对数字的和进行排序,因此需要自定义一个比较函数,自己定义一个堆处理成对的数据结构。
每次我们取出了(i,j)对元素之后,接下来按理需要放进去(i+1,j)和(i,j+1)。但是在(i+1,j-1)判断的时候同样会加入(i+1,j),这样就重复了。那怎么解决呢?
除了第一行元素加入右边和下面的元素之外,其他元素都只加入下面的元素。
class Solution {
public:
vectorint , int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) {
vectorint ,int> > res;
if (nums1.empty() || nums2.empty() || k <= 0)
return res;
//创建一个堆
auto compare = [&nums1,&nums2](pair<int,int> a,pair<int,int>b){
return nums1[a.first]+nums2[a.second] > nums1[b.first]+nums2[b.second];
};
priority_queue< pair<int,int>,vectorint ,int> >, decltype(compare) > heap(compare);
heap.emplace(0,0);
while(k-- && !heap.empty())
{
auto index = heap.top();
heap.pop();
res.emplace_back(nums1[index.first],nums2[index.second]);
if(index.first+11,index.second);
if(index.first==0 && index.second+11);
}
return res;
}
};
结果:16ms