zoukankan      html  css  js  c++  java
  • [leetcode] 4-寻找两个有序数组的中位数

    给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。

    请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。

    你可以假设 nums1 和 nums2 不会同时为空。

    Input: nums1 = [1, 3]
    nums2 = [2]

    Output: 则中位数是 2.0

    2.思路

    1.外排
    由于数组是有序的,因此可以用外排,将两个数组marge成另外的数组help[]。从有序数组help中找出中位数就是一件简单的事了。(缺点是需要额外的空间来构造一个有序的新数组。)

    实际时间复杂度为O(m+n),空间复杂度为O(m+n)。

    2.双指针法
    定义两个指针分别指向两个数组的开头。若数组总数num为奇数,则查找第num/2个数;若总数为偶数,则找那两个/2.
    (这里不提供代码)

    时间复杂度O(m+n),空间复杂度O(1)。

    3. 二分法查找
    一般时间复杂度为O(logn)的算法,都是需要用到分治思想(且一般为二分)。
    两个有序数组求中位数,问题一般化为,求两个有序数组的第k个数,当k = (m+n)/2时为原问题的解。
    怎么求第k个数?分别求出第一个和第二个数组的第 k / 2个数 a 和 b,然后比较 a 和 b,当a < b ,说明第 k 个数位于 a数组的第 k / 2个数后半段,或者b数组的 第 k / 2 个数前半段,问题规模缩小了一半,然后递归处理就行。

    时间复杂度O(log m+n),空间复杂度O(1)

    源码来源:https://leetcode-cn.com/problems/median-of-two-sorted-arrays/solution/zhen-zheng-ologmnde-jie-fa-na-xie-shuo-gui-bing-pa/

    3.题解

    外排法

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

    二分查找法

    class Solution {
        public double findMedianSortedArrays(int[] nums1, int[] nums2) {
            int m = nums1.length;
            int n = nums2.length;
            //处理任何一个nums为空数组的情况
            if (m == 0) {
                if (n % 2 != 0)
                    return 1.0 * nums2[n / 2];
                return (nums2[n / 2] + nums2[n / 2 - 1]) / 2.0;
            }
            if (n == 0) {
                if (m % 2 != 0)
                    return 1.0 * nums1[m / 2];
                return (nums1[m / 2] + nums1[m / 2 - 1]) / 2.0;
            }
            int total = m + n;
            //总数为奇数,找第 total / 2 + 1 个数
            if ((total & 1) == 1) {
                return find_kth(nums1, 0, nums2, 0, total / 2 + 1);
            }
            //总数为偶数,找第 total / 2 个数和第total / 2 + 1个数的平均值
            return (find_kth(nums1, 0, nums2, 0, total / 2) + find_kth(nums1, 0, nums2, 0, total / 2 + 1)) / 2.0;
    
        }
    
        //寻找a 和 b 数组中,第k个数字
        double find_kth(int[] a, int a_begin, int[] b, int b_begin, int k) {
            //当a 或 b 超过数组长度,则第k个数为另外一个数组第k个数
            if (a_begin >= a.length)
                return b[b_begin + k - 1];
            if (b_begin >= b.length)
                return a[a_begin + k - 1];
            //k为1时,两数组最小的那个为第一个数
            if (k == 1)
                return Math.min(a[a_begin], b[b_begin]);
    
            int mid_a = Integer.MAX_VALUE;
            int mid_b = Integer.MAX_VALUE;
            //mid_a / mid_b 分别表示 a数组、b数组中第 k / 2 个数
            if (a_begin + k / 2 - 1 < a.length)
                mid_a = a[a_begin + k / 2 - 1];
            if (b_begin + k / 2 - 1 < b.length)
                mid_b = b[b_begin + k / 2 - 1];
            //如果a数组的第 k / 2 个数小于b数组的第 k / 2 个数,表示总的第 k 个数位于 a的第k / 2个数的后半段,或者是b的第 k / 2个数的前半段
            //由于范围缩小了 k / 2 个数,此时总的第 k 个数实际上等于新的范围内的第 k - k / 2个数,依次递归
            if (mid_a < mid_b)
                return find_kth(a, a_begin + k / 2, b, b_begin, k - k / 2);
            //否则相反
            return find_kth(a, a_begin, b, b_begin + k / 2, k - k / 2);
        }
    }
    
    
    花五年时间成为某个领域的专家
  • 相关阅读:
    POJ 1003 解题报告
    POJ 1004 解题报告
    POJ-1002 解题报告
    vi--文本编辑常用快捷键之光标移动
    常用图表工具
    September 05th 2017 Week 36th Tuesday
    September 04th 2017 Week 36th Monday
    September 03rd 2017 Week 36th Sunday
    September 02nd 2017 Week 35th Saturday
    September 01st 2017 Week 35th Friday
  • 原文地址:https://www.cnblogs.com/sang-bit/p/11716670.html
Copyright © 2011-2022 走看看