(可忽略中间直接跳到最后一段的代码)
写在前面的废话
小渣渣的leetcode之旅
刚拿到这道题第一个是想到用类似归并的算法逐个逐个数,然后找到中间的数,不过觉得既然是标为hard的题觉得这种做法时间发咋度较高。然后产生了第二个想法,就是在数组1和数组2都找中间数num1[p1],num2[p2],然后比较两者,再慢慢比较两者,通过挪动p1和p2最终找到两者数组的中间数。无奈这种方法考虑的情况比较多,最终以失败告终。于是,还是上网学习了一下别人的代码,找到了一种比价容易实现好理解的方法,就是将找中间数转化为找第k大的数。
基本思路是:在num1和num2中找到p1和p2(两者及其前面的数加起来共k个),然后比较num1[p1]和num2[p2],假设num1[p1] < num2[p2],则删去num1前p1个数,改为寻找两个数组的第k-p1大的数,以此类推,递归函数。
注意边界情况:其中一个数组为空的话则返回另一个数组的第k大值。
代码如下:
#include<iostream>
#include<vector>
using namespace std;
double findKth(vector<int> n1, int size1, vector<int> n2, int size2, int k){
if (size1 < size2) //把数组1定为两者中较大者可以简化程序
return findKth(n2, size2, n1, size1, k);
if (size2 == 0)//其中一个数组为空的情况,直接返回另一数组第k大值
return n1[k - 1];
if (k == 1)//由于p1和p2及其前面的数加起来至少有2个,所以需要将1个的情况分开讨论
{
if (!size1) return n2[0];
if (!size2) return n1[0];
return min(n1[0],n2[0]);
}
int mid2 = min(k/2,size2); int mid1 = k - mid2;//分配p1、p2,写的时候用的是mid1 = p1-1、mid2 =p2-1
mid1--;
mid2--;
if (n1[mid1] > n2[mid2])
{
if (mid2 + 1 == size2) return findKth(n1, size1, n2, 0 , k - mid2 - 1);//不单独讨论该情况的话,传n2数组会因为越界报错
vector<int> v(n2.begin()+mid2+1,n2.end());
return findKth(n1, size1, v,size2 - mid2 - 1, k - mid2 - 1);
}
else if (n1[mid1] < n2[mid2])
{
if (mid1 + 1 == size1) return findKth(n1, 0, n2, size2 , k - mid1 - 1);
vector<int> v(n1.begin()+mid1+1,n1.end());
return findKth(v, size1 - mid1 - 1, n2, size2, k - mid1 - 1);
}
else return n1[mid1];//两者相等,则n1[mid1] = n2[mid2],其大小恰好为第k个值的大小
}
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int size1 = nums1.size();
int size2 = nums2.size();
int kk = (size1+size2)/2+1;
if ((size1 + size2)%2 == 1)
return findKth(nums1,nums1.size(),nums2,nums2.size(),kk);//两个数组总数为奇数
else {
double a =findKth(nums1,nums1.size(),nums2,nums2.size(),kk-1);
double b =findKth(nums1,nums1.size(),nums2,nums2.size(),kk);
return (a+b)/2;//两个数组总数为偶数
}
}
};
int main(){
vector<int> n1;
vector<int> n2;
n1.push_back(3);
n1.push_back(4);
n2.push_back(1);
n2.push_back(2);
Solution s1;
cout << s1.findMedianSortedArrays(n1,n2);
return 0;
}
之前真有点啰嗦。有空再整理整理。
class Solution {
public:
double findK(vector<int>& nums1,int start1,vector<int>& nums2,int start2,int k)
{
if (start1 >= nums1.size()) return nums2[start2+k-1];
if (start2 >= nums2.size()) return nums1[start1+k-1];
if (k == 1) return min(nums1[start1],nums2[start2]);
int s1 = start1 + (k>>1) , s2 = start2 + (k>>1) ;
s1 = s1 >= nums1.size() ? nums1.size() : s1;
s2 = s2 >= nums2.size() ? nums2.size() : s2;
if (nums1[s1-1] <= nums2[s2-1])
return findK(nums1,s1,nums2,start2,k - (s1 - start1));
else return findK(nums1,start1,nums2,s2,k - (s2 - start2));
}
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2)
{
int size1 = nums1.size(),size2= nums2.size();
if ((size1 + size2) & 1)
return findK(nums1,0,nums2,0,((size1+size2)>>1)+1);
else return (findK(nums1,0,nums2,0,((size1+size2)>>1)+1)+findK(nums1,0,nums2,0,(size1+size2)>>1))/2.0;
}
};