zoukankan      html  css  js  c++  java
  • 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)).

    题意:

    两个排序后的数组nums1 和nums2,长度分别是m,n,找出其中位数,并且时间复杂度:O(log(m+n))

     

    最愚蠢的方法:

    两个数组合并成一个,排序,取出中位数

    Java程序:

    public class Solution {
        public double findMedianSortedArrays(int[] nums1, int[] nums2) {
            int m = nums1.length;
            int n = nums2.length;
            int median_index = (m+n)/2;
            int nums[] = new int[m+n];
            if(m!=0)
                for(int k=0;k<m;k++)
                    nums[k] = nums1[k];
            if(n!=0)
                for(int k=0;k<n;k++)
                    nums[m+k] = nums2[k];
            Arrays.sort(nums);
            if((m+n)%2==1)
                return nums[median_index];
            else 
                return (nums[median_index]+nums[median_index-1])/2.0;
        }
    }

    无耻的又用Python实现了一遍

    class Solution(object):
        def findMedianSortedArrays(self, nums1, nums2):
            """
            :type nums1: List[int]
            :type nums2: List[int]
            :rtype: float
            """
            m = len(nums1)
            n = len(nums2)
            median_index = (m+n)/2
            nums=[num for num in nums1]
            for num in nums2:
                nums.append(num)
            nums.sort()
            if((m+n)%2==1):
                return nums[median_index]
            else:
                return (nums[median_index]+nums[median_index-1])/2.0

    说明一下:

    Python中 sorted(list)排序是直接返回排序后的结果,原list没有改变,而list.sort() 不返回排序后的结果,结果更新list

     

    正确方法:

    问题转化为:nums1和nums2合并排序后的第k个元素

    主要思想是:每次剔除部分对求第k个元素没有用的数据

    假设nums1和nums2原始序列是升序的,则是求合并后升序的第k个元素,或者第k大元素

    假设nums1和nums2原始序列是降序的,则是求合并后降序的第k个元素,或者第k小元素

    下面假设是升序

    m = nums1.length

    n = nums2.length

    若 nums1是空的,结果就是 nums2[k]

    若 nums2是空的,结果就是 nums1[k]

    若 k==0,返回nums1[0] 、nums2[0]中的较小者

    对于其他情况:

    为了好说明,定义变量:nums1Start,nums1End,nums2Start,nums2End

    我们要求的是合并后的第k大的数

    小于第k大的数是没有用的

    对于合并排序后的前k个数,理想情况下,是均匀的分布在nums1 和nums2中

    k个数中nums1中占:nums1Mid = nums1Len*k/(nums1Len+nums2Len)个  这里除法取的是下界

    k个数中nums2中占:nums2Mid = k – nums1Mid – 1 个 这里是因为下标是从0开始

    由于我们定义了开始位置,则:

    nums1Mid = nums1Mid + nums1Start

    nums2Mid = nums2Mid + nums2Start

    下面比较这两个位置对应元素的大小:nums1[nums1Mid ]   nums2[nums2Mid]

    若:nums1[nums1Mid ]  > nums2[nums2Mid]  说明:第k大的数在nums1中的nums1Start 到nums1Mid 之间  和 nums2 中nums2Mid 到nums2End之间

    可以发现我们去除的有效部分只是nums2中的nums2Start 到 nums2Mid之间的元素,而nums1中 nums1Mid到nums1End之间的原始已经是大于 第k个元素了。

    所以更新k,k = k - (nums2Mid – nums2Start + 1)

    同时更新:nums1End = nums1Mid  ,nums2Start = nums2Mid + 1,其他不变

    若:nums1[nums1Mid ]  < nums2[nums2Mid]  说明:第k大的数在num1中的num1Mid到nums1End之间 和 nums2中的nums2Start到nums2Mid之间

    更新k,k = k - (nums1Mid – nums1Start + 1)

    同时更新: nums1Start = nums1Mid + 1,nums2End = nums2Mid ,其他不变

    若:nums1[nums1Mid ]  = nums2[nums2Mid]

    这里正好是第k个数,就是所求答案

    对于上面两种情况,继续递归求解

    关于时间复杂度:在最坏的情况下,每次都要去除k/2的元素,则log(k) = log((m+n)/2) = log(m+n)

    Java程序:

    public class Solution {
        public double findMedianSortedArrays(int[] nums1, int[] nums2) {
            int m = nums1.length;
            int n = nums2.length;
            if((m+n)%2==1)//odd
                return (double)findKth(nums1,0,m-1,nums2,0,n-1,((m+n)/2));
            else
                return (findKth(nums1,0,m-1,nums2,0,n-1,(m+n)/2)+findKth(nums1,0,m-1,nums2,0,n-1,(m+n)/2-1))/2.0;
        }
        
        public int findKth(int[] nums1,int nums1Start,int nums1End,int[] nums2,int nums2Start,int nums2End,int k){
            int nums1Len = nums1End - nums1Start + 1;
            int nums2Len = nums2End - nums2Start + 1;
            if(nums1Len ==0)
                return nums2[nums2Start+k];
            if(nums2Len ==0)
                return nums1[nums1Start+k];
            if(k==0)
                return nums1[nums1Start]<nums2[nums2Start] ? nums1[nums1Start]:nums2[nums2Start];
            int nums1Mid = nums1Len*k/(nums1Len+nums2Len);
            int nums2Mid = k - nums1Mid - 1 ;
            nums1Mid = nums1Mid + nums1Start;
            nums2Mid = nums2Mid + nums2Start;
            if(nums1[nums1Mid] > nums2[nums2Mid]){
                k = k - (nums2Mid - nums2Start + 1);
                nums1End = nums1Mid;
                nums2Start = nums2Mid + 1;
            }else if(nums1[nums1Mid] < nums2[nums2Mid]){
                k = k - (nums1Mid - nums1Start + 1);
                nums2End = nums2Mid;
                nums1Start = nums1Mid + 1;
            }else 
                return nums1[nums1Mid];
            return findKth(nums1,nums1Start,nums1End,nums2,nums2Start,nums2End,k);
        }
        
    }

     

    程序参考

    对于降序的情况:

    当是降序的时候,出来这个结果:

    image

    在网上找个C++程序,当是降序的时候,上面的输入也是2.0000,上面给的期望答案也是2.0000

     

    然后我就试试这个输入

    image

    上面的C++程序和上面的Java程序都是输入6.0000

     

    题目中没有说升序的啊,但是许多人都默认升序做了,降序输入结果就不对了。

    上面的Java程序和上面C++程序原理是很类似的,但是只能对升序求解,降序数组下标需要修改,大于和小于 和上面的恰好相反

     

    好吧,咱就当升序的数组处理。上面的都对。

     

    既然是升序,尝试用两个变量指向两个数组的开始位置,比较大小,异步前进,发现,,,,,,,,,,,,,,,,坑太大,检测中间点的可能太多,,,,,或者定义许多boolean变量检测 ,,,,,,,,,,,不写了,,是写的不对。。。已乱。。。

     

    又转换成Python代码:

    class Solution(object):
        def findMedianSortedArrays(self, nums1, nums2):
            """
            :type nums1: List[int]
            :type nums2: List[int]
            :rtype: float
            """
            nums1Len = len(nums1)
            nums2Len = len(nums2)
            if (nums1Len + nums2Len)%2==1:
                return 1.0*self.findKth(nums1,0,nums1Len-1,nums2,0,nums2Len-1,(nums1Len + nums2Len)/2)
            return (self.findKth(nums1,0,nums1Len-1,nums2,0,nums2Len-1,(nums1Len + nums2Len)/2)+self.findKth(nums1,0,nums1Len-1,nums2,0,nums2Len-1,(nums1Len + nums2Len)/2-1))*0.5
            
            
        def findKth(self,nums1,nums1Start,nums1End ,nums2,nums2Start,nums2End,k):
            nums1Len = nums1End - nums1Start + 1
            nums2Len = nums2End - nums2Start + 1
            if nums1Len==0 : return nums2[nums2Start + k]
            if nums2Len==0 : return nums1[nums1Start + k]
            if k==0: return min(nums1[nums1Start],nums2[nums2Start])
            nums1Mid = nums1Len*k/(nums1Len + nums2Len)
            nums2Mid = k - nums1Mid - 1
            nums1Mid += nums1Start
            nums2Mid += nums2Start
            if nums1[nums1Mid]== nums2[nums2Mid]:
                return nums2[nums2Mid]
            if nums1[nums1Mid] > nums2[nums2Mid]:
                k = k - (nums2Mid - nums2Start + 1)
                nums1End = nums1Mid 
                nums2Start = nums2Mid + 1
            if nums1[nums1Mid] < nums2[nums2Mid]:
                k = k - (nums1Mid - nums1Start + 1)
                nums2End = nums2Mid 
                nums1Start = nums1Mid + 1
            return self.findKth(nums1,nums1Start,nums1End,nums2,nums2Start,nums2End,k)

     

  • 相关阅读:
    这是另外一篇
    使用客户端写博客
    vim编码相关配置
    给eclipse装一些插件
    手机型号收集
    解决黑苹果与windows时区不一致
    记录一些在VPS上折腾的东西
    一个获取文件绝对路径的sh
    python批量GBK转UTF-8
    用NDK编译lua库
  • 原文地址:https://www.cnblogs.com/theskulls/p/4856370.html
Copyright © 2011-2022 走看看