4. 寻找两个正序数组的中位数

算法题(程序员面试宝典)

解题思路主要来源于leetcode官方与《程序员面试宝典》。

4. 寻找两个正序数组的中位数

给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。

示例 1:

输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2
示例 2:

输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5
示例 3:

输入:nums1 = [0,0], nums2 = [0,0]
输出:0.00000
示例 4:

输入:nums1 = [], nums2 = [1]
输出:1.00000
示例 5:

输入:nums1 = [2], nums2 = []
输出:2.00000

解题方法

思路来源:https://leetcode-cn.com/problems/median-of-two-sorted-arrays/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-w-2/

解题思路1

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        //合并数组,再找中位数
        int m = nums1.length;
        int n = nums2.length;
        //特殊情况,一方长度为0,直接返回
        if(m==0){
            if(nums2.length%2==0){
                return (nums2[(nums2.length/2)-1]+nums2[nums2.length/2])/2.0;
            }else{
                return nums2[nums2.length/2];
            }
        }
        if(n==0){
            if(nums1.length%2==0){
                return (nums1[(nums1.length/2)-1]+nums1[nums1.length/2])/2.0;
            }else{
                return nums1[nums1.length/2];
            }
        }
        //合并数组
        int[] nums = new int[nums1.length+nums2.length];
        int count = 0;
        int i=0,j=0;
        while(count!=(m+n)){
            if(i==m){
                //nums1 数组已遍历结束
                while(j!=n){
                    nums[count++]=nums2[j++];
                }
                break;
            }
            if(j==n){
            //nums2 数组已遍历结束
                while(i!=m){
                    nums[count++]=nums1[i++];
                }
                break;
            }
            if(nums1[i]>nums2[j]){
                nums[count++] = nums2[j++];
            }else{
                nums[count++] = nums1[i++];
            }
        }

        //返回中位数
        if((m+n)%2==0){
            return (nums[((m+n)/2)-1]+nums[(m+n)/2])/2.0;
        }else{
            return nums[(m+n)/2];
        }
    }
}

解题思路2

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        //双指针思想
        int m = nums1.length;
        int n = nums2.length;
        int len = m+n;
        // 存储中位数的值
        int left = -1,right = -1;
        // 遍历数组的指针
        int aStart = 0,bStart = 0;
        for(int i = 0;i<=(len/2);i++){
            //更新left的值
            left = right;
            if(aStart<m&&(bStart>=n||nums1[aStart]<nums2[bStart])){
                //1 nums1未遍历结束且nums1[aStart]<nums2[bStart]  
                //2 nums1未遍历结束且nums2遍历结束
                right = nums1[aStart++];
            }else{
                right = nums2[bStart++];
            }
        }
        if(len%2==0){
            return (left+right)/2.0;
        }else{
            return right;
        }
    }
}

解题思路3

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        //二分思想  将问题转换为找第k个小数  (递归解法)
        int m = nums1.length;
        int n = nums2.length;
        int left = (m+n+1)/2;
        int right = (m+n+2)/2;
        return (getKth(nums1,0,m-1,nums2,0,n-1,left)+getKth(nums1,0,m-1,nums2,0,n-1,right))*0.5;
    }

    public int getKth(int[] nums1,int astart,int aend,int[] nums2,int bstart,int bend,int k){
        int len1 = aend - astart +1;
        int len2 = bend - bstart +1;
        //让 len1 的长度小于 len2,这样就能保证如果有数组空了,一定是 len1 
        if(len1>len2)
            return getKth(nums2,bstart,bend,nums1,astart,aend,k);
        // 数组1为空时,返回数组2的第k个小数
        if(len1==0)
            return nums2[bstart+k-1];

        if(k==1)
            return Math.min(nums1[astart],nums2[bstart]);
        
        //每次淘汰 k/2 个值小的数(当长度不够k/2时,排除len个 值小的数) 
        int i = astart + Math.min(len1,k/2) -1;
        int j = bstart + Math.min(len2,k/2) -1;

        if(nums1[i]>nums2[j]){
            return getKth(nums1,astart,aend,nums2,j+1,bend,k-(j-bstart+1));
        }else{
            return getKth(nums1,i+1,aend,nums2,bstart,bend,k-(i-astart+1));
        }   
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值