zoukankan      html  css  js  c++  java
  • 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 };
  • 相关阅读:
    MySQL模糊匹配查询like、regexp、in
    MySQL数据库——表操作
    (转)MySQL join语法解析与性能分析
    (转)解决 TortoiseGit 诡异的 Bad file number 问题
    四、windows下TortoiseGit的使用与操作
    (转)创建GitHub技术博客
    二、Windows下TortoiseGit的安装与配置
    三、TortoiseGit之配置密钥
    集训之6-26模拟赛一
    集训之各种dp
  • 原文地址:https://www.cnblogs.com/xiaozhuyang/p/6123007.html
Copyright © 2011-2022 走看看