题目:

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

题解:

  第一次解Hard级的题,果然不是现在的我能做得了的。暴力解肯定不行(即用分治法将两个数组排序,然后计算中位数),题目规定了时间复杂度,只能从网上看大神的了。一是将问题扩大成寻找第K大的元素,先简单的实现,不考虑题目规定的时间复杂度。(Two Pointers思想)

Solution 1(46ms)

 class Solution {
public:
int findKth(vector<int> nums1, vector<int> nums2, int k) {
int m = nums1.size(), n = nums2.size();
int p = , q = ;
for(int i=; i<k-; i++) {
if(p>=m && q<n) q++;
else if(q>=n && p<m) p++;
else if(nums1[p]>nums2[q]) q++;
else p++;
}
if(p>=m) return nums2[q];
else if(q>=n) return nums1[p];
else return min(nums1[p],nums2[q]);
}
int findKth2(vector<int> nums1, vector<int> nums2, int k) {
int m = nums1.size(), n = nums2.size();
int i = , j = , cur = ;
while(i<m&&j<n) {
if(nums1[i]<nums2[j]) {
cur++;
if(cur==k) return nums1[i];
i++;
}
else {
cur++;
if(cur==k) return nums2[j];
j++;
}
}
while(i<m) {
cur++;
if(cur==k) return nums1[i];
i++;
}
while(j<n) {
cur++;
if(cur==k) return nums2[j];
j++;
}
}
double findMedianSortedArrays(vector<int> nums1, vector<int> nums2) {
int total = nums1.size() + nums2.size();
if(total % ==){
return (findKth(nums1,nums2,total/)+findKth(nums1,nums2,total/+))/2.0;
} else {
return findKth(nums1,nums2,total/+);
}
}
};

  时间复杂度为O(k)=O(m+n),原因在于findKth函数。那么怎么进行优化呢?实际上与O(logn)有关的算法第一个想到的就是二分思想。

  如果想要时间复杂度将为O(log(m+n))。我们可以考虑从K入手。如果我们每次能够删除一个一定在第K个元素之前的元素,那么我们需要进行K次,但是如果每次我们都删除一半呢?由于两个数组都是有序的,我们应该充分利用这个信息。
  假设A B 两数组的元素都大于K/2,我们将A B两数组的第K/2个元素进行比较。比较的结果有三种情况。
    A[K/2] == B[K/2];     A[K/2] > B[K/2];    A[K/2] <= B[K/2]
  如果 A[K/2] < B[K/2] 意味着 A[0] 到 A[K/2] 肯定在A∪B的前k个元素中。因此我们可以放心删除A数组的这个k/2个元素。同理A[K/2] > B[K/2]。
  如果 A[K/2] == B[K/2] 说明已经找到了第K个元素,直接返回A[K/2]或者B[K/2]。(from here)

  另外,需要处理边界条件:

  如果A或者B为空,则直接返回B[k-1]或者A[k-1];如果k为1,我们只需要返回A[0]和B[0]中的较小值;如果A[k/2-1]=B[k/2-1],返回其中一个;(from here

  上述的描述不太准确,知道这个思想就好了。

Solution 2 ()

class Solution {
public:
double findKth(vector<int> nums1, vector<int> nums2, int k) {
int m = nums1.size(), n = nums2.size();
if(m <= ) return nums2[k-];
if(n <= ) return nums1[k-];
if(k <= ) return min(nums1[], nums2[]);
if(nums2[n/] >= nums1[m/]) {
if((m/ + + n/) >= k) {
return findKth(nums1, vector<int> (nums2.begin(), nums2.begin()+n/), k);
}
else
return findKth(vector<int> (nums1.begin()+m/+, nums1.end()), nums2, k-(m/+));
}
else {
if((m/ + + n/) >= k) {
return findKth(vector<int> (nums1.begin(), nums1.begin()+m/), nums2, k);
}
else
return findKth(nums1, vector<int> (nums2.begin()+n/+, nums2.end()),k-(n/+));
}
}
double findMedianSortedArrays(vector<int> nums1, vector<int> nums2) {
int m = nums1.size(), n = nums2.size();
if((m + n) % == )
return (findKth(nums1, nums2, (m+n)/) + findKth(nums1, nums2, (m+n)/+))/2.0;
else
return findKth(nums1, nums2, (m+n)/+);
}
};

  Solution 2 代码简化

Solution 3 (82ms)

 class Solution {
public:
int findKth(vector<int> nums1, vector<int> nums2, int k) {
int m = nums1.size(), n = nums2.size();
//确保m<=n
if (m > n)
return findKth(nums2, nums1, k);
if (m == )
return nums2[k - ];
if (k == )
return min(nums1[], nums2[]);
int i = min(m, k / ), j = k-i;
if (nums1[i - ] > nums2[j - ])
return findKth(nums1, vector<int>(nums2.begin() + j, nums2.end()), k - j);
else
return findKth(vector<int>(nums1.begin() + i, nums1.end()), nums2, k - i); }
double findMedianSortedArrays(vector<int> nums1, vector<int> nums2) {
int total = nums1.size() + nums2.size();
if(total % ==){
return (findKth(nums1,nums2,total/)+findKth(nums1,nums2,total/+))/2.0;
} else {
return findKth(nums1,nums2,total/+);
}
}
};

    减少vector数组的复制开销,

Solution 4

 class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int m = nums1.size(), n = nums2.size();
int total = m + n;
if (total % == ) {
return (findKth(nums1, , m, nums2, , n, total / ) + findKth(nums1, , m, nums2, , n, total / + )) / 2.0;
} else {
return (findKth(nums1, , m, nums2, , n, total / + ));
}
} double findKth(vector<int>& nums1, int begin1, int end1, vector<int>& nums2, int begin2, int end2, int K) {
int len1 = end1 - begin1, len2 = end2 - begin2;
if (len1 > len2)
return findKth(nums2, begin2, end2, nums1, begin1, end1, K);
if (len1 < ) return nums2[begin2 + K - ];
if (len2 < ) return nums1[begin1 + K - ];
if (K < ) return min(nums1[begin1], nums2[begin2]); int mid1 = min(len1, K / ), mid2 = K - mid1;
if (nums1[begin1 + mid1 - ] > nums2[begin2 + mid2 - ])
return findKth(nums1, begin1, end1, nums2, begin2 + mid2, end2, K - mid2);
else
return findKth(nums1, begin1 + mid1, end1, nums2, begin2, end2, K - mid1); }
};

Solution 5 (76ms)

  这个就比较牛了,具体细节在这里。 

This problem is notoriously hard to implement due to all the corner cases. Most implementations consider odd-lengthed and even-lengthed arrays as two different cases and treat them separately. As a matter of fact, with a little mind twist. These two cases can be combined as one, leading to a very simple solution where (almost) no special treatment is needed.

First, let's see the concept of 'MEDIAN' in a slightly unconventional way. That is:

"if we cut the sorted array to two halves of EQUAL LENGTHS, then
median is the AVERAGE OF Max(lower_half) and Min(upper_half), i.e. the
two numbers immediately next to the cut".
For example, for [ ], we make the cut between and : [ / ]
then the median = (+)/. Note that I'll use '/' to represent a cut, and (number / number) to represent a cut made through a number in this article. for [ ], we make the cut right through like this: [ (/) ] Since we split into two halves, we say now both the lower and upper subarray contain . This notion also leads to the correct answer: ( + ) / = ; For convenience, let's use L to represent the number immediately left to the cut, and R the right counterpart. In [2 3 5 7], for instance, we have L = 3 and R = 5, respectively. We observe the index of L and R have the following relationship with the length of the array N: N Index of L / R
/
/
/
/
/
/
/
/
It is not hard to conclude that index of L = (N-)/, and R is at N/. Thus, the median can be represented as (L + R)/ = (A[(N-)/] + A[N/])/
To get ready for the two array situation, let's add a few imaginary 'positions' (represented as #'s) in between numbers, and treat numbers as 'positions' as well. [ ] -> [# # # # #] (N = )
position index (N_Position = ) [ ]-> [# # # # # #] (N = )
position index (N_Position = )
As you can see, there are always exactly *N+ 'positions' regardless of length N. Therefore, the middle cut should always be made on the Nth position (-based). Since index(L) = (N-)/ and index(R) = N/ in this situation, we can infer that index(L) = (CutPosition-)/, index(R) = (CutPosition)/. Now for the two-array case: A1: [# # # # # #] (N1 = , N1_positions = ) A2: [# # # # #] (N2 = , N2_positions = )
Similar to the one-array problem, we need to find a cut that divides the two arrays each into two halves such that "any number in the two left halves" <= "any number in the two right
halves".
We can also make the following observations: There are 2N1 + 2N2 + position altogether. Therefore, there must be exactly N1 + N2 positions on each side of the cut, and positions directly on the cut. Therefore, when we cut at position C2 = K in A2, then the cut position in A1 must be C1 = N1 + N2 - k. For instance, if C2 = , then we must have C1 = + - C2 = . [# # # # (/) # #] [# / # # #]
When the cuts are made, we'd have two L's and two R's. They are L1 = A1[(C1-)/]; R1 = A1[C1/];
L2 = A2[(C2-)/]; R2 = A2[C2/];
In the above example, L1 = A1[(-)/] = A1[] = ; R1 = A1[/] = A1[] = ;
L2 = A2[(-)/] = A2[] = ; R2 = A1[/] = A1[] = ;
Now how do we decide if this cut is the cut we want? Because L1, L2 are the greatest numbers on the left halves and R1, R2 are the smallest numbers on the right, we only need L1 <= R1 && L1 <= R2 && L2 <= R1 && L2 <= R2
to make sure that any number in lower halves <= any number in upper halves. As a matter of fact, since
L1 <= R1 and L2 <= R2 are naturally guaranteed because A1 and A2 are sorted, we only need to make sure: L1 <= R2 and L2 <= R1. Now we can use simple binary search to find out the result. If we have L1 > R1, it means there are too many large numbers on the left half of A1, then we must move C1 to the left (i.e. move C2 to the right);
If L2 > R1, then there are too many large numbers on the left half of A2, and we must move C2 to the left.
Otherwise, this cut is the right one.
After we find the cut, the medium can be computed as (max(L1, L2) + min(R1, R2)) / ;
Two side notes: A. since C1 and C2 can be mutually determined from each other, we might as well select the shorter array (say A2) and only move C2 around, and calculate C1 accordingly. That way we can achieve a run-time complexity of O(log(min(N1, N2))) B. The only edge case is when a cut falls on the 0th(first) or the 2Nth(last) position. For instance, if C2 = 2N2, then R2 = A2[*N2/] = A2[N2], which exceeds the boundary of the array. To solve this problem, we can imagine that both A1 and A2 actually have two extra elements, INT_MAX at A[-] and INT_MAX at A[N]. These additions don't change the result, but make the implementation easier: If any L falls out of the left boundary of the array, then L = INT_MIN, and if any R falls out of the right boundary, then R = INT_MAX.
 class Solution {
public:
double findMedianSortedArrays(vector<int> nums1, vector<int> nums2) {
int m = nums1.size();
int n = nums2.size();
if (m < n) return findMedianSortedArrays(nums2, nums1);
if (n == ) return ((double)nums1[(m-)/] + (double)nums1[m/])/;
int i = , j = n * ;
while (i <= j) {
int mid2 = (i + j) / ;
int mid1 = m + n - mid2;
double L1 = (mid1 == ) ? INT_MIN : nums1[(mid1-)/];
double L2 = (mid2 == ) ? INT_MIN : nums2[(mid2-)/];
double R1 = (mid1 == m * ) ? INT_MAX : nums1[(mid1)/];
double R2 = (mid2 == n * ) ? INT_MAX : nums2[(mid2)/];
if (L1 > R2) i = mid2 + ;
else if (L2 > R1) j = mid2 - ;
else return (max(L1,L2) + min(R1, R2)) / ;
}
return -;
}
};

【LeetCode】004. Median of Two Sorted Arrays的更多相关文章

  1. 【LeetCode】4. Median of Two Sorted Arrays (2 solutions)

    Median of Two Sorted Arrays There are two sorted arrays A and B of size m and n respectively. Find t ...

  2. 【LeetCode】4. Median of Two Sorted Arrays 寻找两个正序数组的中位数

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 公众号:负雪明烛 本文关键词:数组,中位数,题解,leetcode, 力扣,python ...

  3. 【leetcode】4. Median of Two Sorted Arrays

    题目描述: There are two sorted arrays nums1 and nums2 of size m and n respectively. Find the median of t ...

  4. 【LeetCode】4.Median of Two Sorted Arrays 两个有序数组中位数

    题目: There are two sorted arrays nums1 and nums2 of size m and n respectively. Find the median of the ...

  5. 【LeetCode】4. Median of Two Sorted Arrays(思维)

    [题意] 给两个有序数组,寻找两个数组组成后的中位数,要求时间复杂度为O(log(n+m)). [题解] 感觉这道题想法非常妙!! 假定原数组为a,b,数组长度为lena,lenb. 那么中位数一定是 ...

  6. 【一天一道LeetCode】#4 Median of Two Sorted Arrays

    一天一道LeetCode (一)题目 There are two sorted arrays nums1 and nums2 of size m and n respectively. Find th ...

  7. 【leetcode】1213.Intersection of Three Sorted Arrays

    题目如下: Given three integer arrays arr1, arr2 and arr3 sorted in strictly increasing order, return a s ...

  8. 【LeeetCode】4. Median of Two Sorted Arrays

    There are two sorted arrays nums1 and nums2 of size m and n respectively. Find the median of the two ...

  9. 【medium】4. Median of Two Sorted Arrays 两个有序数组中第k小的数

    There are two sorted arrays nums1 and nums2 of size m and n respectively. Find the median of the two ...

随机推荐

  1. 架构在APP和前端里的应用和演进

    架构设计相关的理念.技术.实践,比如存储高可用.微服务.异地多活等,都是后端系统才会涉及.事实上确实也是如此,通常情况下我们讲架构设计,主要聚焦在后端系统,但这并不意味着 App.前端就没有架构设计了 ...

  2. 【TopCoder】SRM159 DIV2总结

    250分题:给出一些规则,问街道上哪些地方可以停车. 简单的模拟题,考察每条规则是否成立即可. 代码:StreetParking 500分题:实现集合的交,并和差运算. 交运算:一个数组放到集合中,遍 ...

  3. HAproxy 配置参数详解

    HAproxy 配置参数详解 /etc/haproxy/haproxy.cfg # 配置文件 ----------------------------------------------------- ...

  4. 主攻ASP.NET.4.5.1 MVC5.0之重生:系统角色与权限(一)

    数据结构 权限分配 1.在项目中新建文件夹Helpers 2.在HR.Helpers文件夹下添加EnumMoudle.Cs namespace HR.Helpers { public enum Enu ...

  5. CSS3手风琴菜单 可同时折叠多个菜单

    在线演示 本地下载

  6. android studio Error:Unable to start the daemon process【转】

    本文转载自:https://blog.csdn.net/dhx20022889/article/details/44919905 我在用android studio 做一个小项目,在家里的mac电脑中 ...

  7. Mybatis-config.xml配置文件详解

    1.官方给出的案列: 注意:这些配置在文件中的顺序非常重要!必须严格按照上图中出现的顺序定义 2.properties属性 该属性主要作用就是引入外部的properties是文件,文件格式为xxx=x ...

  8. showModalDialog改进版,包括Chrome下的特殊处理

    父页面: if(window.ActiveXObject){ //IE          $("#choose_entp").click(function(){           ...

  9. nginx流量全copy记录

    参考:http://tyrion.iteye.com/blog/2311987 准备两台服务器: 0.0.0.1 0.0.0.2 在 0.0.0.1上 . 下载 wget https://github ...

  10. 简学Python第五章__模块介绍,常用内置模块

    Python第五章__模块介绍,常用内置模块 欢迎加入Linux_Python学习群  群号:478616847 目录: 模块与导入介绍 包的介绍 time &datetime模块 rando ...