归并排序思想求两个有序数组的中位数

栏目: 编程工具 · 发布时间: 7年前

内容简介:归并排序思想求两个有序数组的中位数

原题

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

题目分析

这道题目在Leetcode上属于难度hard级别。

归并 <a href='https://www.codercto.com/topics/21904.html'>排序</a> 思想求两个有序数组的中位数

此题的基本思想可以借鉴归并排序。

第一步,先对两个有序列归并排序,不同的是当进行到一半时,便可终止归并,得到 i

j 分别指向两个有序数组此时的位置。

第二步,如果两个数组的 总个数为奇数 ,则返回 i

j 所指向的元素的更大者即可;

若为偶数,需要利用 i

j 所指向的元素大小进行讨论。
  • i 所指向的元素更大,则循环中最后的遍历落在了 n u m s 1 中,那么,如果 i 1 > = 0 (即 i 前存在前一个元素)且 n u m s 1 [ i 1 ] > = n u m s 2 [ j ] ,则中位数为 ( n u m s 1 [ i 1 ] + n u m s 1 [ i ] ) / 2.0
  • 如果 i 1 = = 0 或者 n u m s 1 [ i 1 ] < n u m s 2 [ j ] ,则中位数为 ( n u m s 1 [ i ] + n u m s 2 [ j ] ) / 2.0 ;若落在了 n u m s 2 中,则对称地进行讨论。

需要注意的是边界情况,例如 n u m s 1 = 1 , n u m s 2 = k o n

代码实现

public double FindMedianSortedArrays(int[] nums1, int[] nums2) {
            int n1 = nums1.Length, n2 = nums2.Length, i = 0, j = 0;

            // sorting nums1 and nums2, sum pointer
            int sumpointer = 0; 
            for (i = 0, j = 0; (i < n1 || j < n2) && sumpointer <= (n1 + n2) >> 1; sumpointer++){
            //indicates nums1.Length<nums2.Length          
                if (i >= n1) j++;     
                //nums1.Length>nums2.Length                        
                else if (j >= n2) i++;
                //combination nums1 and nums2 to sort
                else if (nums1[i] <= nums2[j]) i++; 
                else j++;
            }

            bool even = (n1 + n2) % 2 == 0;
            --i; --j;
            if (i < 0) return even == true ? (nums2[j - 1] + nums2[j]) / 2.0 : nums2[j];
            if (j < 0) return even == true ? (nums1[i - 1] + nums1[i]) / 2.0 : nums1[i];

            //odd analysis
            if (!even) return Math.Max(nums1[i], nums2[j]);

            //even analysis
            //shows stone point is in nums2
            if (nums1[i] < nums2[j]){ 
                if (j - 1 >= 0 && nums1[i] <= nums2[j - 1])
                    return (nums2[j - 1] + nums2[j]) / 2.0;
                return (nums1[i] + nums2[j]) / 2.0;
            }
            // shows stone point is in nums1
            if (i - 1 >= 0 && nums2[j] <= nums1[i - 1])
                return (nums1[i - 1] + nums1[i]) / 2.0;
            return (nums1[i] + nums2[j]) / 2.0;

    }

结果分析:
时间复杂度为 O ( 0.5 ( m + n ) )

,空间复杂度为 O ( 1 ) ,计算结果排名:

归并排序思想求两个有序数组的中位数

以下是我之前写的一篇归并排序博客,地址,在此一块汇总到这里。
http://blog.csdn.net/daigualu/article/details/68491601

归并排序

归并排序( MERGE-SORT )是建立在归并操作上的一种有效的排序算法,该算法是采用分治法( Divide and Conquer )的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列。

排序过程

归并排序的算法我们通常用递归实现,先把待排序区间 [start,end] 以中点二分,接着把左边子区间排序,再把右边子区间排序,这是分解的过程。最后把左区间和右区间用一次归并操作合并成有序的区间 [start,end] ,这是治理的过程。如何归并呢? 简单来说两个指针分别指向待归并的数组,选出较小的,放到第三个指针控制的临时数组中。

实现代码

主题框架代码如下,见代码注释。

 /// <summary>
        /// 主题框架
        /// </summary>
        private void divideMerge(int[] unsort, int start, int end, int[] sort)
        {
            if (start < end)
            {
                int middle = (start + end) >> 1;
                //对前半部分归并排序
                divideMerge(unsort, start, middle, sort); 
                //对后半部分归并排序
                divideMerge(unsort, middle + 1, end, sort); 
                //此时,前、后半部分已经是有序序列,对它们实行二路归并
                merge(unsort, start, middle, end, sort);
            }

        }

调用的二路归并方法merge的实现代码如下,要特别注意临界值,此处pe为最大索引值,而不是元素个数,注意此处。

/// <summary>
        /// 合并算法
        /// </summary>
        /// <param name="unsort">无序数组</param>
        /// <param name="ps">第1部分的起始位置</param>
        /// <param name="pm">第1部分的结束位置</param>
        /// <param name="pe">第2部分的结束位置</param>
        /// <param name="sort"></param>
        private void merge(int[] unsort, int ps, int pm, int pe, int[] sort)
        {
            int i = ps; //第一部分的取值范围为[ps,pm]
            int j = pm+1; //第二部分的取值范围为[pm+1,pe]

            int sortCount = 0;

            while (i <= pm && j <= pe)
            {
                if (unsort[i] < unsort[j])
                    sort[sortCount++] = unsort[i++];
                else
                    sort[sortCount++] = unsort[j++];
            }

            while (i <= pm)
                sort[sortCount++] = unsort[i++];

            while (j <= pe)
                sort[sortCount++] = unsort[j++];

            for (int sortIndex = 0; sortIndex < sortCount; sortIndex++)
                unsort[ps + sortIndex] = sort[sortIndex];

        }

封装了一个排序类,见下,提供的API有2个,

  1. 归并排序接口MergeSort()
  2. 构造函数,构造无序数组
public class CMergeSort
    {
        private int[] _unsortArray;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="unsortArray"></param>
        public CMergeSort(int[] unsortArray)
        {
            _unsortArray = unsortArray;
        }

        /// <summary>
        /// 归并排序接口
        /// </summary>
        /// <returns></returns>
        public int[] MergeSort()
        {
            int maxIndex = _unsortArray.GetUpperBound(0);
            int[] sort = new int[maxIndex + 1];
            divideMerge(_unsortArray, 0, maxIndex, sort);
            return sort;
        }
  }

客户端调用

客户端调用刚才写好的对象,对无序数组a实行归并排序。

static void Main(string[] args)
        {
            int[] a = new int[] { 9,7,10,6,3,5,2,7,9};
            var merge = new CMergeSort(a);
            int[] sortArray = merge.MergeSort();

            Console.Read();
        }

记录了归并排序的过程,对此进行了结果分析。

结果分析

对数组的 { 9,7,10,6,3,5,2,7,9} 的归并排序过程如下,


归并排序思想求两个有序数组的中位数

归并排序过程的前半部分,过程示意图见下,从图中可见,步骤 1234 一直分割区间,等到步骤 5 时,左右区间长度都为1,此时发生一次归并,结果再与另一个区间长度为1的归并,即步骤 6 ;步骤 7 分割,步骤 8 归并,步骤 9 归并后前半部分合并结束;
后半部分过程与前半部分归并一致,不再详述。

归并排序思想求两个有序数组的中位数

源码下载

http://download.csdn.net/detail/daigualu/9799598

我做Leetcode的专栏

http://blog.csdn.net/column/details/14761.html

汇总在GitHub上

地址,欢迎一起讨论!若有问题请联系我!
https://github.com/jackzhenguo/leetcode-csharp


以上所述就是小编给大家介绍的《归并排序思想求两个有序数组的中位数》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

劫持

劫持

玛丽•K. 斯温格尔(Mari K. Swingle) / 邓思渊 / 中信出版集团股份有限公司 / 2018-5-1 / CNY 59.00

《劫持》是一本探讨人与科技的关系的书,基于一位心理学博士20年的临床经验及其作为神经认知科学研究者的脑—电研究成果。在这本面向大众的科普书中,作者以深入浅出的方式,探讨了手机、电脑等便携式数字设备及让人“永不下线”的互联网对现代人尤其是青少年大脑的影响,从神经认知科学和精神分析的角度,有力地证明了数字媒介与大脑和人类行为的关系,探讨了手机等如何对人的大脑进行劫持或操控,并给出了自己作为从业医师的实......一起来看看 《劫持》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具