【LeetCode】【数组】【二分】4. 寻找两个正序数组的中位数 Java实现(四种方案,目前写了两种,还在更新)

本文探讨了在LeetCode问题中寻找两个已排序数组的中位数的两种方法:一是归并数组后找中位数,二是直接在数组间比较。第一种方法涉及合并操作,第二种则利用了数组特性简化过程。两种方法的时间复杂度均为O(m+n),空间复杂度分别为O(m+n)和O(1)。
摘要由CSDN通过智能技术生成


题目链接

https://leetcode.cn/problems/median-of-two-sorted-arrays/

题目

在这里插入图片描述

我的思路

归并排序的思想,因为nums1和nums2已经是有序的,所以把两个数组中的结果放到一个新的数组中,检查index是否已经指向中位数的位置,如果是的话,在根据nums1和nums2两个数组长度总和是奇数还是偶数进行判断,是直接返回一个数值,还是两个数加和求平均再返回

在这里插入图片描述

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {

        int totalLength = nums1.length + nums2.length;
        int[] nums = new int[totalLength];
        int i = 0, j = 0;
        int index = 0;
        while (i < nums1.length && j < nums2.length) {
            if (nums1[i] < nums2[j]) {
                nums[index] = nums1[i++];
            } else if (nums1[i] > nums2[j]) {
                nums[index] = nums2[j++];
            } else {
                nums[index] = nums1[i++];
            }
            if (index == totalLength / 2) {
                //nums数组长度为偶数
                if ((totalLength & 1) == 0) {
                    return (nums[index] + nums[index - 1]) / 2.0;
                } else {
                    //nums数组长度是奇数
                    return 1.0 * nums[index];
                }
            }
            index++;
        }
        if (i == nums1.length) {
            while (j <= nums2.length) {
                nums[index] = nums2[j++];
                if (index == totalLength / 2) {
                    //nums数组长度为偶数
                    if ((totalLength & 1) == 0) {
                        return (nums[index] + nums[index - 1]) / 2.0;
                    } else {
                        //nums数组长度是奇数
                        return 1.0 * nums[index];
                    }
                }
                index++;
            }
        }
        if (j == nums2.length) {
            while (i < nums1.length) {
                nums[index] = nums1[i++];
                if (index == totalLength / 2) {
                    //nums数组长度为偶数
                    if ((totalLength & 1) == 0) {
                        return (nums[index] + nums[index - 1]) / 2.0;
                    } else {
                        //nums数组长度是奇数
                        return 1.0 * nums[index];
                    }
                }
                index++;
            }
        }
        return 0.0;
    }
}

就代码而言,感觉还是有一定的冗余,不精炼

其他解法

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

方案一 合并两个数组

先将两个数组合并,两个有序数组的合并也是归并排序的一部分,然后根据是奇数、还是偶数,返回中位数

和我的思路一样,不过代码看上去更简洁一些

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

        //如果nums1数组的长度为0,只要返回nums2数组的中位数即可
        if (m == 0) {

            if ((n & 1) != 0) {
                return nums2[n / 2];
            } else {
                return (nums2[n / 2] + nums2[n / 2 - 1]) / 2.0;
            }

        } else if (n == 0) {

            if ((m & 1) != 0) {
                return nums1[m / 2];
            } else {
                return (nums1[m / 2] + nums1[m / 2 - 1]) / 2.0;
            }
        }
        int count = 0;
        int i = 0, j = 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 ((count & 1) != 0) {
            return nums[count / 2];
        }
        return (nums[count / 2] + nums[count / 2 - 1]) / 2.0;
    }

}

时间复杂度

遍历整个数组,O(m+n)

空间复杂度

开辟了一个数组,保存两个数组合并以后的结果O(m+n)

方案二 不用合并数组,找到中位数即可

如何将奇数和偶数的情况合并?

用len表示合并后数组的长度

  • 如果是奇数,需要知道l第en/2+1个数字是什么,需要遍历len/2+1个数

    • 是奇数,需要最后一次的遍历结果
  • 如果是偶数,需要知道第len/2个数字和第len/2+1个数字是什么,也需要遍历len/2+1个数

    • 是偶数,需要最后一次和上一次的遍历结果

用两个变量,pre和now,now保存当前循环的结果,在每次循环前将now的值赋值给pre。这样在最后一次循环的时候,pre将得到right的值,也就是上一次循环的结果,接下来,now更新为最后一次的结果
在这里插入图片描述

循环中,分别用aStart和bStart分别表示当前指向nums1数组和nums2数组的位置。

如果aStart没有到最后,并且nums1中aStart位置上的数字小于nums2中bStart位置上的数字,那么,aStart可以往后移,也就是 aStart < m && nums1[aStart] < nums2[bStart]。

上面的条件表达式,如果nums2数组已经遍历到头了,再取nums2[bStart]会数组越界,抛出异常,所以,要判断一下bStart是否大于等于nums2的数组长度,这样 || 后面的nums1[aStart] < nums2[bStart]就不会执行了,也就不会导致错误了。所以,增加为 aStart < m && (bStart >= n || nums1[aStart] < nums2[bStart])
在这里插入图片描述

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int m = nums1.length;
        int n = nums2.length;
        int len = m + n;
        int aStart = 0, bStart = 0;
        int pre = -1, now = -1;
        for (int i = 0; i <= len / 2; i++) {
            pre = now;
            if (aStart < m && (bStart >= n || nums1[aStart] < nums2[bStart])) {
                now = nums1[aStart++];
            } else {
                now = nums2[bStart++];
            }
        }
        if ((len & 1) != 1) {
            return (pre + now) / 2.0;
        }
        return now * 1.0;
    }
}

时间复杂度

遍历len/2+1次,len=m+n,所以,时间复杂度依旧是O(m+n)

空间复杂度

申请了常数个变量,所以是O(1)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值