首页 > 代码库 > LeetCode4. Median of Two Sorted Arrays---vector实现O(log(m+n)--- findkth

LeetCode4. Median of Two Sorted Arrays---vector实现O(log(m+n)--- findkth

这道题目和PAT上的1029是同一题。但是PAT1029用O(m+n)的时间复杂度(题解)就可以,这道题要求是O(log(m+n))。

这道题花费了我一个工作日的时间来思考。因为是log因而一直思考如何进行二分,想着是两个vector分别二分,但一直想不到合适的解法,就是无穷尽的if else

后来看了题解。思路是从两个有序数组中寻找第k小的数。

<1>花了很长时间在调试上,结果发现是少了一个return,期间还不停怀疑自己写递归的能力。。。要被自己打败了,调代码真是一件细小却很耗费心神的事情。

<2>对vector的使用也是醉了。

思路如下:

  我们先假设nums1nums2数组中元素个数都是大于 k/2 的,且从 0 开始编号,那么我们比较 a = nums1[k/2 - 1] 和 b = nums2[k/2 - 1]。

  (1)如果 a < b 那么 nums1[0] 到 nums1[k/2 - 1] 这 k/2 个数在合并后的有序数组中,一定在第 k 小的数左边。为什么呢?

  我们发现,nums1数组中比 a 小的数一共是 k/2 - 1 个。nums2数组中比 a 小的数最多有 k/2 - 1 个。因而合并以后比 a 小的数最多有k/2 - 1 + k/2 - 1 < k - 2。

  也就是说 a 最多是第 k-1 小的数。所以说nums1数组前 k/2 个数可以剔除了。

  (2)如果 a > b 同理,剔除掉 nums2数组前 k/2 个数。

  (3)如果 a = b,a 即为所求。

  每次剔除掉 k 一半个元素,因而时间复杂度是O(logk),对于此题,k = (m+n)/2 所以时间复杂度是O(log(m+n))

 

考虑实际情况:

  如果nums1nums2数组中元素个数不足 k/2 个的话,一般情况下,我们只需要满足两者前面的总数目为 k 即可,原理和上述的原理是类似的,不再赘述。

  此外还需要考虑特殊情况,

  (1)一个数组为空,则放回另一个数组的第 k 大;

  (2)k==1则直接返回min(nums1[0],nums2[0])。

在实际实现的时候,由于输入是vector,它是一个动态数组,可以实时增加或删除元素,但是无法向普通数组/指针一样任意指定起始位置和结束为止,因而只好使用了删除操作

erase(iter1,iter2),删除[iter1,iter2)之间的元素。 

 1 class Solution {
 2 public:
 3     double findkth(vector<int>& nums1,vector<int>& nums2, int k)
 4     {
 5         int m = nums1.size(),n = nums2.size();
 6         if(m > n)
 7             return findkth(nums2,nums1,k);//error 1. forget the "return";
 8         if(m == 0)
 9             return double(nums2[k - 1]);//error 2. write as nums2[n - 1];
10         if(k == 1)
11         {
12             return double(min(nums1[0],nums2[0]));
13         }
14         int pa = min(k / 2,m), pb = k - pa;
15         if(nums1[pa - 1] < nums2[pb - 1])
16         {
17             nums1.erase(nums1.begin(),nums1.begin() + pa);
18             return findkth(nums1,nums2,k - pa);
19         }
20         else if(nums1[pa - 1] > nums2[pb - 1])
21         {
22             nums2.erase(nums2.begin(),nums2.begin() + pb);
23             return findkth(nums1,nums2,k - pb);
24         }
25         else
26             return double(nums1[pa - 1]);
27     }
28     double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
29         int len1 = nums1.size(),len2 =  nums2.size();
30         int len = len1 + len2;
31         vector<int> cop1(nums1),cop2(nums2);
32         if(len % 2)
33         {
34             return findkth(nums1,nums2,len / 2 + 1);
35         }
36         else
37         {
38             double t1=findkth(nums1,nums2,len / 2),t2=findkth(cop1,cop2,len / 2 + 1);
39             return (t1 + t2) / 2;
40         }
41     }
42 };

 

删除vector的元素需要①额外备份一下数组,②删除操作。无谓的耗时,因而重新实现成手动标记数组的起始位置。只需要在上面实现方法的基础上 + star就可以了,原理都是一样的。

 1 class Solution {
 2 public:
 3     double findkth(vector<int>& nums1,int st1,int ed1,vector<int>& nums2, int st2,int ed2,int k)
 4     {
 5         int m = ed1 - st1,n = ed2 - st2;
 6         if(m > n)
 7             return findkth(nums2,st2,ed2,nums1,st1,ed1,k);//error 1. forget the "return";
 8         if(m == 0)
 9             return double(nums2[st2 + k - 1]);//error 2. write as nums2[n - 1];
10         if(k == 1)
11         {
12             return double(min(nums1[st1],nums2[st2]));
13         }
14         int pa = min(k / 2,m), pb = k - pa;
15         if(nums1[st1 + pa - 1] < nums2[st2 + pb - 1])
16         { 
17             return findkth(nums1,st1 + pa,ed1,nums2,st2,ed2,k - pa);
18         }
19         else if(nums1[st1 + pa - 1] > nums2[st2 + pb - 1])//error 3. forget the "st2 +";
20         {
21             return findkth(nums1,st1,ed1,nums2,st2 + pb,ed2,k - pb);
22         }
23         else
24             return double(nums1[st1 + pa - 1]);
25     }
26     double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
27         int len1 = nums1.size(),len2 =  nums2.size();
28         int len = len1 + len2;
29         if(len % 2)
30         {
31             return findkth(nums1,0,len1,nums2,0,len2,len / 2 + 1);
32         }
33         else
34         {
35             double t1 = findkth(nums1,0,len1,nums2,0,len2,len / 2),t2 = findkth(nums1,0,len1,nums2,0,len2,len / 2 + 1);
36             return (t1 + t2) / 2;
37         }
38     }
39 };

 

LeetCode4. Median of Two Sorted Arrays---vector实现O(log(m+n)--- findkth