Leetcode_Problem4_Median of Two Sorted Arrays(两种解法)

题目

问题网址:
https://leetcode.com/problems/median-of-two-sorted-arrays/description/
问题描述:
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

解决方法

方法一:借助临时数组(以空间换时间)

主要思想:
这种解法的思想比较简单,主要是利用一个临时数组,先将两个有序的数组进行排序,然后判断数据总数目是奇数还是偶数,取相应的中位数。主要需要考虑的是数组的排序性能,数组排序的主要思想如下图:
这里写图片描述
实现代码:

#include <iostream>
#include <vector>
using namespace std;

double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
    int m = nums1.size(), n = nums2.size();
    vector<int> temp;
    int i = 0, j = 0;

    //当数组nums1和nums2都不为空时,先加入小的数据,再加入大的数据
    while((i < m) && (j < n)){
        if(nums1[i] <= nums2[j]){
            temp.push_back(nums1[i]);
            ++i;
        }else{
            temp.push_back(nums2[j]);
            ++j;
        }
    }

    //若数组nums1和nums2有一个为空,则不需要判断上述过程,采用下面的解决方法
    //直接将剩余的数组元素添加到temp
    if(i < m){
        for( int k = i; k < m; ++k){
            temp.push_back(nums1[k]);
        }
    }
    if(j < n){
        for( int k = j; k < n; ++k){
            temp.push_back(nums2[k]);
        }
    }

    //对temp数组的大小分奇数和偶数讨论
    if((m+n)%2==1){
        return temp[(m+n-1)/2];
    }else{
        return (temp[(m+n)/2-1]+temp[(m+n)/2])/2.0;
    }
}

int main()
{
    vector<int> nums1, nums2;
    nums1.push_back(2);
    nums1.push_back(3);
    nums2.push_back(6);
    cout << findMedianSortedArrays(nums1, nums2) << endl;
    return 0;
}

Submission Detail:

2080 / 2080 test cases passed.                       
Status: Accepted
Runtime: 69 ms         

方法二:利用数据特点

主要思想:
注:本方法思想和代码主要来自Leetcode讨论区。
Step1:
(1)假设数组A在下标为i处被切分,如下:

         left_A        |         right_A
  A[0],A[1],...,A[i-1] | A[i], A[i+1], ..., A[m-1] 

因数组A共有m个元素,所以数组有m+1种,即在下标0~m处切分都可以。若len(left_A) = i,则len(right_A) = m-i;若len(left_A) = 0,则len(right_A) = m。
(2)同样,B也是如此,

         left_B        |         right_B
  B[0],B[1],...,B[j-1] | B[j], B[j+1], ..., B[n-1] 

(3)将 A A B的左半部分和右半部分合并,如下图:

      left_part        |        right_part
  A[0],A[1],...,A[i-1] | A[i], A[i+1], ..., A[m-1] 
  B[0],B[1],...,B[j-1] | B[j], B[j+1], ..., B[n-1] 

(4)如我们可以保证:

i) len(left_part) == len(right_part)
ii) max(left_part) <= min(right_part)

则我们可将A+B分成相同长度的两部分。若总数据数目是奇数,则中位数是max(left_part)或者min(right_part),若总数据数目是偶数,则中位数是(max(left_part)+min(right_part))/2。
(5)可将问题转化为如下:

i) i + j = m - i + n - j(若总数目为奇数,则是m - i + n - j + 1)
若n > m, 我们只需要设置: i = 0 ~ m, j = (m + n + 1)/2 - i
ii) B[j-1] <= A[i] 或者 A[i-1] <= B[j]

(6)因上述涉及到A[i-1], B[j-1], A[i], B[j],所以需要对i=0, i=m, j=0, j=n这几个边界值进行讨论。
    (i)上述设置n > m的原因是为了保证当0 <= i <= m时,j=(m + n + 1)/2 - i 的值非负。
      (ii)问题转化为:

Searching i in [0, m], to find an object `i` that:
    B[j-1] <= A[i] and A[i-1] <= B[j], ( where j = (m + n + 1)/2 - i )

(7)使用二分查找,可有如下分析:

<1> Set imin = 0, imax = m, then start searching in [imin, imax]

<2> Set i = (imin + imax)/2, j = (m + n + 1)/2 - i

<3> Now we have len(left_part)==len(right_part). And there are only 3 situations
     that we may encounter:
    <a> B[j-1] <= A[i] and A[i-1] <= B[j]
        Means we have found the object `i`, so stop searching.
    <b> B[j-1] > A[i]
        Means A[i] is too small. We must `ajust` i to get `B[j-1] <= A[i]`.
        Can we `increase` i?
            Yes. Because when i is increased, j will be decreased.
            So B[j-1] is decreased and A[i] is increased, and `B[j-1] <= A[i]` may
            be satisfied.
        Can we `decrease` i?
            `No!` Because when i is decreased, j will be increased.
            So B[j-1] is increased and A[i] is decreased, and B[j-1] <= A[i] will
            be never satisfied.
        So we must `increase` i. That is, we must ajust the searching range to
        [i+1, imax]. So, set imin = i+1, and goto <2>.
    <c> A[i-1] > B[j]
        Means A[i-1] is too big. And we must `decrease` i to get `A[i-1]<=B[j]`.
        That is, we must ajust the searching range to [imin, i-1].
        So, set imax = i-1, and goto <2>.

当i确定后,中位数如下:

max(A[i-1], B[j-1]) (when m + n is odd)
or (max(A[i-1], B[j-1]) + min(A[i], B[j]))/2 (when m + n is even)

Step2:
考虑边界值情况:i=0, i=m, j=0, j=n。
我们需要讨论的情况如下:

Searching i in [0, m], to find an object `i` that:
    (j == 0 or i == m or B[j-1] <= A[i]) and
    (i == 0 or j == n or A[i-1] <= B[j])
    where j = (m + n + 1)/2 - i

对在代码中可能遇到的问题,下面分类讨论:

<a> (j == 0 or i == m or B[j-1] <= A[i]) and
    (i == 0 or j = n or A[i-1] <= B[j])
    Means i is perfect, we can stop searching.

<b> j > 0 and i < m and B[j - 1] > A[i]
    Means i is too small, we must increase it.
    其实,i < m ⇒ j > 0:m <= n, i < m ==> j = (m+n+1)/2 - i > (m+n+1)/2 - m >= (2*m+1)/2 - m >= 0  

<c> i > 0 and j < n and A[i - 1] > B[j]
    Means i is too big, we must decrease it.
    其实,i > 0j < n:m <= n, i > 0 ==> j = (m+n+1)/2 - i < (m+n+1)/2 <= (2*n+1)/2 <= n

实现代码:

#include <iostream>
#include <vector>
using namespace std;

double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
    int m = nums1.size(), n = nums2.size();
    //下面程序的作用是保证数组nums1是短的那个,而nums2是长的那个
    vector<int> tempArr;
    int temp;
    if(m > n){
        tempArr = nums1;
        nums1 = nums2;
        nums2 = tempArr;
        temp = m;
        m = n;
        n = temp;
    }

    int imin = 0, imax = m, half_len=(m+n+1)/2, max_of_left, min_of_right, i, j;

    while(imin <= imax){
        i = (imin + imax)/2;  //i使用二分法的思想
        j = half_len - i;  //j的更新条件
        if((i < m) && (nums2[j-1] > nums1[i])){  //非边界情况
            imin = i + 1;
        }else if((i > 0) && (nums1[i-1] > nums2[j])){   //非边界情况
            imax = i - 1;
        }else{
            //考虑边界情况
            if(i==0){
                max_of_left = nums2[j-1];
            }else if( j == 0){
                max_of_left = nums1[i-1];
            }else{
                max_of_left = max(nums1[i-1], nums2[j-1]);
            }

            if((m+n)%2==1){   //奇数处理
                return max_of_left;
            }

            if(i==m){  //偶数处理
                min_of_right = nums2[j];
            }else if(j ==n ){
                min_of_right = nums1[i];
            }else{
                min_of_right = min(nums1[i], nums2[j]);
            }
            return (max_of_left + min_of_right)/2.0;
        }
    }
}

int main()
{
    vector<int> nums1, nums2;
    nums1.push_back(2);
    nums1.push_back(3);
    nums2.push_back(1);
    nums2.push_back(6);
    cout << findMedianSortedArrays(nums1, nums2) << endl;
    return 0;
}

Submission Detail:

2080 / 2080 test cases passed.                       
Status: Accepted
Runtime: 47 ms         
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看READme.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值