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);
        }
    }
    
    
    花五年时间成为某个领域的专家
  • 相关阅读:
    《原創》實現禁止 WTL CTabView 中標籤的拖曳行為。 (Disable Dragging Operation of CTabView)
    《轉貼》ATL NTService 運作流程
    《轉貼》WTL 之 m_hWndMDIClient
    《原創》加強版的 C++ 字串型別
    《原創》建立最基礎的 Irrlicht 3D 引擎的應用框架。(for vc2008)
    《轉貼》關於 ios::app 與 ios::ate 簡易說明
    《轉貼》WTL for MFC programmer 系列文章
    《轉貼》以Virtual Inheritance及Template讓C++能實現C#中的sealed
    Oracle学习笔记(concat和substr)
    Oralce学习笔记(sql取一张表的数据插入另一张表)
  • 原文地址:https://www.cnblogs.com/sang-bit/p/11716670.html
Copyright © 2011-2022 走看看