两个排序数组的中位数

Posted ZeroC

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了两个排序数组的中位数相关的知识,希望对你有一定的参考价值。

 

 
给定两个大小为 m 和 n 的有序数组 nums1 和 nums2 
请找出这两个有序数组的中位数。要求算法的时间复杂度为 O(log (m+n)) 。
你可以假设 nums1 和 nums2 不同时为空。
示例 1:
nums1 = [1, 3] nums2 = [2]
中位数是 2.0
示例 2:
nums1 = [1, 2] nums2 = [3, 4]
中位数是 (2 + 3)/2 = 2.5
 
自我思路:
1.寻找出两个数组合并后中位数的位置
2.从小到大,从两个数组中取出对应位置的数
难点:
1.获取中位数的位置。本人对数字超级混乱,所以如何获取数组的中位数需要留意。
2.按元素大小,遍历两个有序数组的元素,并获取对应的中间的一个或两个数,从而获得中位数。
思路:从两个数组头部开始,比较元素大小,以A[m]和B[n]为例,则这两个长分别为m和n的数组的中位数位置应当是【(m+n-1)/2】或【(m+n-1)/2,(m+n-1)/2+1】。
(1)若A[0]>B[0],则合并后数组的第一个元素是B[0],反之则为A[0]。记为thisNum;
(2)以1中较大数继续与另一数组下一元素比较,获取thisNum。
(3)获取的thisNum是第【(m+n-1)/2】或【(m+n-1)/2,(m+n-1)/2+1】时,便记录下来求中位数。
3.从2的思路出发,可以实现算法的框架,但是会有一些细节问题:
(1)如何记录中位数的位数,是记录一个还是两个
(2)如何制定从小到大遍历数组的规则
算法实现:
  1 import java.io.IOException;
  2 import java.util.Arrays;
  3 import java.util.Scanner;
  4 
  5 public class MedianSortedArrays {
  6     public static void main(String[] args) throws IOException{
  7         /*获取输入内容*/
  8         Scanner input = new Scanner(System.in);
  9         System.out.println("请输入第一个数组,元素间以逗号隔开:");
 10         int[] nums1=stringToArray(input.nextLine());
 11         System.out.println("请输入第二个数组,元素间以逗号隔开:");
 12         int[] nums2=stringToArray(input.nextLine());
 13         System.out.println("这两个数组的中位数是:");
 14         Solution getMedian=new Solution();
 15         Arrays.sort(nums1);
 16         Arrays.sort(nums2);
 17         double median=getMedian.findMedianSortedArrays(nums1,nums2);
 18         System.out.println(median);
 19     }
 20 
 21     /**
 22      * 将获取的字符串转为数组
 23      */
 24     public static int[] stringToArray(String str){
 25         String[] strArr= str.split(",");
 26         int[] arr=new int[strArr.length];
 27         for(int i=0;i<strArr.length;i++){
 28             arr[i]=Integer.parseInt(strArr[i].trim());
 29         }
 30         return arr;
 31     }
 32 }
 33 
 34 
 35 class Solution {
 36     public double findMedianSortedArrays(int[] nums1, int[] nums2) {
 37         double midian;
 38         int[] index=getIndex(nums1.length+nums2.length);
 39         midian=getMedian(nums1,nums2,index);
 40         return midian;
 41     }
 42     
 43     /**
 44      * 获取中位数在组合后的数组中应当存在的位数
 45      * @param arrLength
 46      * @return
 47      */
 48     public int[] getIndex(int arrLength){
 49         int[] index =new int[2];
 50         index[0]=(arrLength-1)/2;//(数组长度-1)/2为中位数在有序数组中的下标之一
 51         if(arrLength%2==0){         //当数组长度为偶数,则中位数是(数组长度-1)/2和(数组长度-1)/2+1这两个下标对应元素的平均值
 52             index[1]=index[0]+1;
 53         }
 54         return index;
 55     }
 56     
 57     /**
 58      * 获取中位数
 59      * @param nums1
 60      * @param nums2
 61      * @param index        中位数下标对应数组[(数组长度-1)/2,(数组长度-1)/2+1]或[(数组长度-1)/2,0]
 62      * @return
 63      */
 64     public double getMedian(int[] nums1, int[] nums2,int[] index){
 65         double sum=0;        //记录中位数对应下标两个元素之和
 66         int maxIndex;        //记录中位数下标数组的较大数
 67         double indexLength;
 68         
 69         /*此处获取中位数最大下标作为循环标记*/
 70         if(index[1]==0){
 71             maxIndex=index[0];
 72             indexLength=1;
 73         }else{
 74             maxIndex=index[1];
 75             indexLength=2;
 76         }
 77         
 78         /*获取两个数组中的对应下标元素之和*/
 79         int j=0,k=0,thisIndex=0,thisNum = 0;
 80         while(thisIndex<=maxIndex){
 81             if(j<nums1.length&&k<nums2.length){ //当两个数组均可遍历时
 82                 if(nums1[j]>=nums2[k]){            //比较元素大小,当某一数组元素小,便推向该数组下一个元素
 83                     thisNum=nums2[k];            //记录比较所得的较小元素,作为thisNum
 84                     k++;
 85                 }else{
 86                     thisNum=nums1[j];
 87                     j++;
 88                 }
 89             }else{                                //当有数组遍历结束,但仍未找到中位数时
 90                 if(j==nums1.length){            //遍历完的数组不再参与thisNum的记录,只进行另外一个数组的遍历
 91                     thisNum=nums2[k];
 92                     k++;
 93                 }
 94                 if(k==nums2.length){
 95                     thisNum=nums1[j];
 96                     j++;
 97                 }
 98             }
 99             
100             if(thisIndex==maxIndex){            //若遍历的次数达到中位数下标要求,便做和,记录中位数相关元素之和
101                 sum+=thisNum;
102             }
103             if(index[1]!=0&&thisIndex==maxIndex-1){
104                 sum+=thisNum;
105             }
106 
107             thisIndex++;                        //遍历标记
108         }
109         return sum/indexLength;                    //返回中位数
110     }
111 }

 

本方案在leetCode提交后,结果运行时间为54ms,而LeetCode最快的结果是32ms
其代码如下
 1 class Solution {
 2     public double findMedianSortedArrays(int[] nums1, int[] nums2) {
 3         int m = nums1.length, n = nums2.length, left = (m + n + 1) / 2, right = (m + n + 2) / 2;
 4         return (findKth(nums1, nums2, left) + findKth(nums1, nums2, right)) / 2.0;
 5     }
 6     int findKth(int[] nums1, int[] nums2, int k) {
 7         int m = nums1.length, n = nums2.length;
 8         if (m > n) return findKth(nums2, nums1, k);
 9         if (m == 0) return nums2[k - 1];
10         if (k == 1) return Math.min(nums1[0], nums2[0]);
11         int i = Math.min(m, k / 2), j = Math.min(n, k / 2);
12         if (nums1[i - 1] > nums2[j - 1]) {
13             return findKth(nums1, Arrays.copyOfRange(nums2, j, n), k - j);
14         } else {
15             return findKth(Arrays.copyOfRange(nums1, i, m), nums2, k - i);
16         }
17     }
18 }

 

 
通过比较可以看得出来,
1.对问题分析的深度和细致还不够,更偏向于暴力破解
2.对递归算法的运用是没有认识的
 
 

以上是关于两个排序数组的中位数的主要内容,如果未能解决你的问题,请参考以下文章

java 两个排序数组的中位数 - 找两个有序数组的中位数

理解“两个排序数组的中位数”的算法

两个排序数组的中位数

Leetcode-两个排序数组的中位数

LeetCode-4. 两个排序数组的中位数(详解)

两个排序数组的中位数