leetcode-寻找两个正序数组的中位数

206 阅读2分钟

这是我参与更文挑战的第4天,活动详情查看: 更文挑战

第4天,继续挑战第4题。这题虽然等级是困难,但是看到给的数据量只有1000,AC过去不算难,但是要达到进阶不容易。

题目

给定两个大小分别为 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

思路

这题要求中位数,如果总个数是奇数,很好理解就是最中间位置的那个数。如果是偶数,就需要拿最中间的2个数来求平均数,实例2也有写。由于这2个数组是有序的,可以用插值排序的方法把2个数组合并成一个大数组,再来求中位数,这样的思路非常清晰,时间复杂度是O(m+n),空间复杂度是O(m+n)。一个优化点是,由于我们用插值法和合并2个有序数组,其实我们只要合并到一半就得到中位数了,不需要完成合并完成,这样时间复杂度是O((m+n)/2),其实还是O(m+n),不过由于就不需要存着新的合并数组,空间复杂度降为O(1)。

注意

注意点就是插值过程中,一个数组已经被遍历完的情况,同理也要注意其中1个数组可能一开始就为空的情况。

Java版本代码

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int len1 = nums1.length;
        int len2 = nums2.length;
        int len = len1 + len2;
        if (len % 2 == 0) {
            // 如果总长度是偶数,需要找到中间的2个数,然后取平均数
            int index = len / 2;
            int start1 = 0;
            int start2 = 0;
            // 序号为index-1的数
            int mmin = 0;
            while (index >= 0) {
                if (start1 < len1 && start2 < len2) {
                    if (nums1[start1] < nums2[start2]) {
                        if (index == 1) {
                            mmin = nums1[start1];
                        } else if (index == 0) {
                            return avg(mmin, nums1[start1]);
                        }
                        start1++;
                    } else {
                        if (index == 1) {
                            mmin = nums2[start2];
                        } else if (index == 0) {
                            return avg(mmin, nums2[start2]);
                        }
                        start2++;
                    }
                } else if (start1 < len1) {
                    if (index == 1) {
                        mmin = nums1[start1];
                    } else if (index == 0) {
                        return avg(mmin, nums1[start1]);
                    }
                    start1++;
                } else {
                    if (index == 1) {
                        mmin = nums2[start2];
                    } else if (index == 0) {
                        return avg(mmin, nums2[start2]);
                    }
                    start2++;
                }
                index--;
            }
        } else {
            // 如果总长度是奇数,最中间位置的数就是中位数
            int index = len / 2;
            int start1 = 0;
            int start2 = 0;
            while (index >= 0) {
                if (start1 < len1 && start2 < len2) {
                    if (nums1[start1] < nums2[start2]) {
                        if (index == 0) {
                            return nums1[start1];
                        }
                        start1++;
                    } else {
                        if (index == 0) {
                            return nums2[start2];
                        }
                        start2++;
                    }
                } else if (start1 < len1) {
                    if (index == 0) {
                        return nums1[start1];
                    }
                    start1++;
                } else {
                    if (index == 0) {
                        return nums2[start2];
                    }
                    start2++;
                }
                index--;
            }
        }
        return -1;
    }

    private static double avg(int a, int b) {
        return (a + b) / 2.0;
    }
}