第四道题,题目如下:

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)).

For example,

nums1 = [1, 3] nums2 = [2] The median is 2.0

nums1 = [1, 2] nums2 = [3, 4] The median is (2 + 3)/2 = 2.5

这道题难在了最后一句有对运行时间的限制,明确的说希望总共的运行时间在O(log(m+n))范围内,但是leetcode的编译器好像没有把这个限制体现出来,导致我第一次写的这个代码也通过了编译,由于nums1和nums2本身已经是排序好的数组了,可以先把这两个数组先合并成一个新的数组,然后找到这个新的数组的中位数,使用javascript代码描述如下:

 1 var findMedianSortedArrays = function(nums1, nums2) {
 2     var result=[];
 3     var i=0
 4     var j=0;
 5     while(i<nums1.length && j<nums2.length){
 6         if(nums1[i]<nums2[j]){
 7             result.push(nums1[i]);
 8             i++;
 9         }
10         else{
11             result.push(nums2[j]);
12             j++;
13         }
14     }
15     
16     while(i<nums1.length){
17         result.push(nums1[i]);
18         i++
19     }
20     
21     while(j<nums2.length){
22         result.push(nums2[j])
23         j++;
24     }
25     
26     if(result.length%2==1){
27         return result[(result.length-1)/2];
28     }
29     else{
30         var tmp=result[result.length/2-1]+result[result.length/2];
31         return tmp/2;
32     }
33 };

这个方法是最简单粗暴的方法,但是仔细看这个的时间复杂度是O(max(n,m)),不符合题目中的时间限制。

既然是求中位数,那么具体中位数所在的位置是知道的,如果nums1,nums2两个数组的长度和是奇数,则表示如果把这两个数组合并,中位数的位置在下标为(nums1.length+nums2.length-1)/2的地方,如果nums1,nums2两个数组的长度和是偶数,则合并后的中位数是下标为(nums1.length+nums2.length)/2-1和下标为(nums1.length+nums2.length)/2的这两个数的平均数。所以主要的问题就是去找合并后对应下标的元素就可以了,也就是当给出两个已经排好序的数组,返回两个数组合并后下标为k的元素。

采取类似二分法的做法,分别比较两个数组中位于下标k/2处的元素,每次判断nums1[k/2]和nums2[k/2]的大小,一次可以去掉k/2+1个元素不用考虑。

有以下情况:

1)在保证nums1始终为长度较短的那个数组的情况下,如果nums1的长度是0,则直接返回nums2[k]

2)如果k为0,则返回nums1[0]和nums2[0]中较小的那个

3)如果k/2大于nums1的最后一个元素的下标值,则令p1=nums1.length-1,否则p1=k/2,p2=k-p1-1

     i)如果nums1[p1]>nums2[p2],应该忽略nums2的前p2+1个元素,则把nums2.slice(p2+1)作为参数递归返回,此时中位数的下标变成了k-p2-1

     ii)如果nums1[p1]<nums2[p2],应该忽略nums1的前p1+1个元素,则把nums2.slice(p1+1)作为参数递归返回,此时中位数的下标变成了k-p1-1

直到k=0或者某个数组的长度变为0就会返回具体的值。

javascript代码描述如下:

 1 var findMedianSortedArrays = function(nums1, nums2) {
 2     var length=nums1.length+nums2.length;
 3     if(length%2===0){
 4         return (findKth(nums1,nums1.length,nums2,nums2.length,length/2-1)
                +findKth(nums1,nums1.length,nums2,nums2.length,length/2))/2; 5 } 6 else{ 7 return findKth(nums1,nums1.length,nums2,nums2.length,(length-1)/2); 8 } 9 }; 10 11 function findKth(nums1,length1,nums2,length2,k){ 12 if(length1>length2){ 13 return findKth(nums2,length2,nums1,length1,k); 14 } 15 if(length1===0){ 16 return nums2[k]; 17 } 18 if(k===0){ 19 return nums1[0]>nums2[0]?nums2[0]:nums1[0]; 20 } 21 var p1=parseInt(k/2)>(length1-1)?(length1-1):parseInt(k/2); 22 var p2=k-p1-1; 23 if(nums1[p1]>nums2[p2]){ 24 nums2=nums2.slice(p2+1); 25 return findKth(nums1,nums1.length,nums2,nums2.length,k-p2-1); 26 } 27 else{ 28 nums1=nums1.slice(p1+1); 29 return findKth(nums1,nums1.length,nums2,nums2.length,k-p1-1); 30 } 31 32 }

同理,使用C++代码描述如下:

 1 class Solution {
 2 public:
 3     double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
 4         int length=nums1.size()+nums2.size();
 5         if(length%2==0){
 6         return (findKth(nums1,nums1.size(),nums2,nums2.size(),length/2-1)
 7             +findKth(nums1,nums1.size(),nums2,nums2.size(),length/2))/2;
 8         }
 9         else{
10             return findKth(nums1,nums1.size(),nums2,nums2.size(),(length-1)/2);
11         }
12     }
13     
14     double findKth(vector<int> nums1,int length1,vector<int> nums2,int length2,int k){
15         if(length1>length2){
16             return findKth(nums2,length2,nums1,length1,k);
17         }
18         if(length1==0){
19             return nums2[k];
20         }
21         if(k==0){
22             return min(nums1[0],nums2[0]); 
23         }
24         int p1=(int)(k/2)>length1-1?length1-1:(int)(k/2);
25         int p2=k-p1-1;
26         if(nums1[p1]<nums2[p2]){
27             nums1.assign(nums1.begin()+p1+1,nums1.end());
28             return findKth(nums1,length1-p1-1,nums2,length2,k-p1-1);
29         }
30         else{
31             nums2.assign(nums2.begin()+p2+1,nums2.end());
32             return findKth(nums1,length1,nums2,length2-p2-1,k-p2-1);
33         }
34     }

 

有关C++知识点总结:

1)区分函数传引用,传值,传指针,函数传值表示函数中对参数的更改不会体现在原始的数据中,只在函数范围内有效,而函数传引用则表示函数中对参数的操作始终和原始数据保持一致,也就是说函数中对参数的所有改变都会体现在原始数据中,而传指针和传引用差不多,把该原始数据所在的地址当作参数进行传递,此时在函数中进行的修改就是直接对原始数据进行修改。

根据上面的说法,findKth函数中的vector参数需要用传值的方式,因为在findKth函数中对vector进行了assign的截取操作,如果传引用则会影响在偶数情况下的取值操作。

2)vector的assign方法,可以作为截取vector中的元素来使用,具体的用法解释是:可以将区间[first,last)的元素赋值到当前的vector容器中,或者赋n个值为x的元素到vector容器中,这个容器会清除掉vector容器中以前的内容。

vector<int> a;
a.assign(a.begin()+1,a.end());   //表示从a的第二个元素开始截取到最后一个元素重新赋值给a
a.assign(10,3);    //表示把原来的容器a清空后,重新初始化为10个3
1 vector<int> a;
2 a.push_back(1);
3 a.push_back(2);
4 a.push_back(3);
5 vector<int> b;
6 b.assign(a.begin()+1, a.end()); //[2,3]

 

有关javascript的知识点总结:

由于javascript的函数都是传值,不存在传引用,所以,就没有像C++那样的考虑,

数组的截取使用方法array.slice(start,end)返回在[start,end)范围内的元素组成的新数组,由于end参数可以省略,如果只有start没有end则默认到原来数组的结尾。

区别数组操作的splice和slice两个方法:

array.slice(start,end) 从数组array中返回指定范围内的元素,注意slice操作不会改变原来array的内容而是会返回一个新的子数组

1 var a=[1,2,3,4,5,6,7,8,9];
2 console.log(a.slice(0,3));  //[1,2,3]
3 console.log(a);  //[1,2,3,4,5,6,7,8,9]

array.splice(index,howmany,item1,.....,itemX):表示删除以下标为index开始的howmany个元素,item1...itemX为可选参数,表示使用item1..itemX来代替那些删除的元素。

1 var a=[1,2,3,4,5,6,7,8,9];
2 a.splice(0,3);
3 console.log(a); //[4,5,6,7,8,9]
1 var a=[1,2,3,4,5,6,7,8,9];
2 a.splice(0,3,10,11);
3 console.log(a);  //[10,11,4,5,6,7,8,9]

 

 posted on 2017-02-07 23:32  yuruilee  阅读(197)  评论(0编辑  收藏  举报