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

两个方法找到两个排序数组的中位数,方法一思路是把两个数组合并成一个数组,然后求中值。这里需要注意的就是当数组个数为偶数时,要除以2.0,最后才能得到double值,否则只能得到整数部分。花费时长6ms。

public class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int m = nums1.length;
        int n = nums2.length;
        int[] nums3 = new int[m + n];
        int i = 0;
        int j = 0;
        int k = 0;
        while(i < m && j < n){
            if(nums1[i] < nums2[j]){
                nums3[k] = nums1[i];
                i++;
            }else if(nums1[i] > nums2[j]){
                nums3[k] = nums2[j];
                j++;
            }else{
                nums3[k] = nums1[i];
                nums3[++k] = nums2[j];
                i++;
                j++;
            }
            k++;
        }
        if(i == m){
            for(int t = j; j < n; j++){
                nums3[k] = nums2[j];
                k++;
            }
        }
        if(j == n){
            for(int t = i; i < m; i++){
                nums3[k] = nums1[i];
                k++;
            }
        }
        if(k % 2 == 0){
            return (nums3[k/2] + nums3[k/2-1]) / 2.0;
        }else{
            return nums3[(k-1)/2];
        }
    }
}

方法二,在discuss中看到一种更为普通的解法,且效率更好。4ms。以下为我的翻译~

首先我们需要明白中位数的作用是什么,它将一个集合分成长度相等的两部分,一边比另一边大。

我们在位置i将A数组分成两部分,A的元素个数为m,共有i=(0~m) m+1个划分位置,len(left_A)=i,len(right_A)=m-i,当i=0时,left_A是空的,当i=m时right_A是空的。


同理,在j位置将B数组划分,B的元素个数是n。


将left_A和left_B放到一组,right_A和right_B放到一组,命名为left_part和right_part。前提是保证m <= n 否则在运行过程中,数组下标会越界。


如果我们能确保


那么就可以得到中位数 median = (max(left_part) + min(right_part))/2.

为了保证上述两个条件,我们只需保证


(假设对所有的A[i-1],B[j-1],A[i],B[j]都是合法的,i=0 或 m, j=0 或 n的情况再单独讨论)

所以我们需要做的就是在i=(0~m)中,找到一个合适的i,使得B[j-1] <= A[i] and A[i-1] <= B[j] (j = (m+n+1)/2-i)。

算法如下:

  1. 使imin = 0, imax = m,在[imin, imax]中找合适的i;
  2. 使i = (imin + imax) / 2,j = (m + n + 1) / 2 - i;
  3. 现在已经保证了len(left_part) == len(right_part),接下来只有3中情况需要讨论:
<a> B[j-1] <= A[i] and A[i-1] <= B[j],意味着找到合适的i,可以停止搜索。
<b> B[j-1] > A[i],意味着找到的i偏小,需要增加i的值,使得A[i]变大,同时B[j-1]变小。set imin = i + 1,调整搜索范围为[i+1,imax]
回到第2步。
<c> A[i-1] > B[j],意味着找到的i偏大,需要减小i的值,set imax = i - 1,然后回到第2步。
找到合适的i以后,
median = max(A[i-1], B[j-1]) (当m + n 是奇数时)
median = (max(A[i-1], B[j-1]) + min(A[i], B[j])) / 2.0 (当m + n 是偶数时 )
接下来讨论边界情况,当i=0,m j=0,n 时,A[i-1],A[i],B[j-1],B[j]都是不存在。
整个过程中,我们需要做的是保证 max(left_part) <= min(right_part)。当上述4个值都存在时,我们需要检查 B[j-1] <= A[i] and A[i-1] <= B[j],
而比如当i=0时,A[i-1]不存在,因此我们不需要检查A[i-1] <= B[j]这个条件。
所以总共有一下三种情况:

public class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int m = nums1.length;
        int n = nums2.length;
        if(m > n){ // 保证m <= n的
            int[] temp = nums1;
            nums1 = nums2;
            nums2 = temp;
            int t = m;
            m = n;
            n = t;
        }
        int imin = 0;
        int imax = m;
        int i, j, max_of_left, min_of_right;
        double mid=0;
        while(imin <= imax){
            i = (imin + imax) / 2;
            j = (m + n + 1) / 2 - i;
            if(j > 0 && i < m && nums2[j - 1] > nums1[i]){ // 当i偏小时
                imin = i + 1;
            }else if(i > 0 && j < n && nums1[i - 1] > nums2[j]){ // 当i偏大时
                imax = i - 1;
            }else{<span style="white-space:pre">	</span>// i在合适位置
                if(i == 0){
                    max_of_left = nums2[j - 1];
                }else if(j == 0){
                    max_of_left = nums1[i - 1];
                }else{
                    max_of_left = Math.max(nums1[i - 1], nums2[j - 1]);
                }
                if((m + n) % 2 ==1){
                    mid = max_of_left;
                    break;
                }
                if(i == m){
                    min_of_right = nums2[j];
                }else if(j == n){
                    min_of_right = nums1[i];
                }else{
                    min_of_right = Math.min(nums1[i], nums2[j]);
                }
                mid = (max_of_left + min_of_right) / 2.0;
                break;
            }
        }
        return mid;
    }
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值