刷题日记3. 寻找两个正序数组中的中位数 -LeetCode

题目

给定两个大小分别为mn的有序数组(从小到大),求这两个数组中的中位数。
例如:

  • nums1=[1,3];nums2=[2] 中位数为2.0000
  • nums1=[1,3];nums2=[2,4] 中位数为(2+3)/2=2.5000
  • nums1=[0,0];nums2=[0,0] 中位数为0
  • nums1=[];nums2=[1] 中位数为1

我的题解

  • 1.将这两个数组合并成一个有序数组,合并后计算其中位数这种做法需要遍历两个数组,并且合成后的数组可能非常大,感觉效率低下

  • 2.我们知道两个数组的长度,那么就知道了中位数的位置n,而且这两个数组是有序的,那么我们遍历两个数组找到第n个大的数就行了。有如下几个问题:

    • 如何确定中位数的位置?如果数组个数为奇数,那么中位数的位置就是lenth/2.0(向上取整),如果数组个数为偶数,那么中位数的位置就是length/2.0和lengrh/2.0+1,可见不管怎样都要用到length/2.0这个数据。
class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {

        //1.计算中位数的位置
        double location=Math.ceil((nums1.length+nums2.length)/2.0);
        //2.定义计数器和指针
        int count=0,i=0,j=0,val1=0,val2=0;
        double mid1=0,mid3=0;
        if(nums1.length==0||nums2.length==0){
            if(nums1.length==0){
                mid1=nums2[(int)location-1];
                if(location<nums2.length)
                mid3=nums2[(int)location];
            }
            if(nums2.length==0){
                mid1=nums1[(int)location-1];
                if(location<nums1.length)
                mid3=nums1[(int)location];
            }
            if((nums1.length+nums2.length)%2==0){
                return (mid1+mid3)/2;
            }else{
                return mid1;
            }
        }else{
            while(i<nums1.length||j<nums2.length){
                val1=nums1[i];
                val2=nums2[j];
                if(i<nums1.length&&val1<val2){
                    i++;
                }else if(j<nums2.length&&val1>=val2){
                    j++;
                }
                count++;

                //判断是否找到中位数
                if(count==location){
                    mid1=val1<val2?val1:val2;
                    break;
                }
         }
        }
       // return mid1;
        if((nums1.length+nums2.length)%2==0){
            //偶数
            double mid2=0;
                if(i<nums1.length&&j<nums2.length){
                    val1=nums1[i];
                    val2=nums2[j];
                    mid2=val2>val1?val1:val2;
                }else if(i<nums1.length){
                    mid2=nums1[i];
                }else if(j<nums2.length){
                    mid2=nums2[j];
                }
            
            //return 10;
            return (mid1+mid2)/2;
        }else{
            //奇数
            return mid1;
        }
    }
}

写了一年,最后还是没通过,怎么说呢 多多少少的还是有问题。不想解决了
直接看官方题解吧

官方题解

解法一:简单粗暴:合并后找中位数

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int m=nums1.length,n=nums2.length;

        //处理有一个数组长度为0的情况
        if(m==0){
            if(n%2==0){
                //偶数
                return (nums2[n/2]+nums2[n/2-1])/2.0;
            }else{
                //奇数
                return nums2[n/2];
            }
        }
        if(n==0){
            if(m%2==0){
                //偶数
                 return (nums1[m/2]+nums1[m/2-1])/2.0;
            }else{
                //奇数
                return nums1[m/2];
            }
        }

        //处理两个数组长度都不为0的情况
        int i=0,j=0;
        int count=0;
        int nums[]=new int[m+n];
        //合并两个数组
        while(count!=m+n){
            //如果有一个数组已经遍历完了
            if(i==m){
                while(j!=n){
                    nums[count++]=nums2[j++];
                }
                break;
            }
            if(j==n){
                while(i!=m){
                    nums[count++]=nums1[i++];
                }
                break;
            }


            if(nums1[i]<nums2[j]){
                nums[count++]=nums1[i++];
            }else{
                nums[count++]=nums2[j++];
            }
        }
        if((m+n)%2==0){
            //偶数
            return (nums[(m+n)/2]+nums[(m+n)/2-1])/2.0;
        }else{
            //奇数
            return nums[(m+n)/2];
        }   
    }
}

在这里插入图片描述

解法二:解法一的优化

  • 我们并不需要对数组全部都进行合并,我们只需要找到中位数在哪里就可以了。
  • 最开始的思路肯定就是写一个循环,然后判断是否到了中位数的位置,到了就返回结果,但是这里对偶数和奇数的分类会很麻烦。当其中一个数组遍历完之后,除了for循环对边界的判断也会分几种情况。
  • 首先是怎么将奇数和偶数的情况合并一下。用len表示合并后数组的长度,如果是奇数,我们需要知道第(len+1)/2个数就可以了,如果遍历的话需要遍历int(len/2)+1次。如果是偶数,我们需要知道第len/2len/2+1个数,也是需要遍历len/2+1次。所以遍历的话,奇数和偶数都是len/2+1次。
    返回中位数的话,奇数只需要最后一次遍历的结果就可以了,偶数需要最后一次和上一次遍历的结果。所以我们用两个变量rightleftright保存当前循环的结果,再每次循环之前将right的值赋给left。这样在最后一次循环的时候,left将得到right的值,也就是上一次循环的结果,接下来right更新为最后一次的结果。
  • 循环该怎么写?什么时候A数组后移,什么时候数组B后移。用aStartbStart分别表示当前指向A数组和B数组的位置。如果aStart还没有到最后并且此时A位置数字小于B位置的数字,那么就可以往后移了。也就是aStart<m&&A[aStart]<B[bStart]
    但是如果B数组此时已经没有数字了,继续取B[bStart],则会越界,所以判断下bStart是否大于数组长度了,这样||后边的就不会再执行了,这样也不会导致错误了,所以增加aStart<m&&(b>=n||A[aStart]<B[bStart])
class Solution {
    public double findMedianSortedArrays(int[] A, int[] B) {
        int n=A.length,m=B.length;
        int length=n+m;
        int aStart=0,bStart=0;
        int left=-1,right=-1;
        while(aStart+bStart<length/2+1){
            left=right;
            if(aStart<n&&(bStart>=m||A[aStart]<B[bStart])){
                right=A[aStart++];
            }else{
                right=B[bStart++];
            }
        }

        //计算中位数
        if((length&1)==0){
            //偶数位
            return (left+right)/2.0;
        }else{
            return right;
        }

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值