LeetCode 4 寻找两个正序数组的中位数(困难)

    科技2024-03-11  93

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

    进阶:你能设计一个时间复杂度为 O(log (m+n)) 的算法解决此问题吗?

    示例 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

    思路与代码

    思路一 双指针(一个指向nums1 一个指向nums2) 按顺序遍历两个数组 找到处于中间位置的数字 时间复杂度 O(m + n)

    来自leetcode中评论区代码

    public double findMedianSortedArrays(int[] A, int[] B) { int m = A.length; int n = B.length; int len = m + n; int left = -1, right = -1; int aStart = 0, bStart = 0; for (int i = 0; i <= len / 2; i++) { left = right; if (aStart < m && (bStart >= n || A[aStart] < B[bStart])) { right = A[aStart++]; } else { right = B[bStart++]; } } if ((len & 1) == 0) return (left + right) / 2.0; else return right; }

    思路二 进阶 时间复杂度 O(log(m+n)) 看到log的时间复杂度,我们就知道肯定跟二分有关

    1 要确定中位数,我们必须要找到中位的分界线num1Line和 num2Line,因为两个数组是分开的,所以每个数组都有各自的分界线。

    2 那么如何找到分界线呢? 我们先确定左边一半的数字大小leftNum,可用两个数组长度的一半来确定。 对其中一个nums1用二分法逼近其分界线,用leftNum - num1Line 来确定数组nums2的分界线num2Line。

    class Solution { public double findMedianSortedArrays(int[] nums1, int[] nums2) { if (nums1.length > nums2.length){ // 将nums1 设为较小长度的数组 int[] temp = nums1; nums1 = nums2; nums2 = temp; } int m = nums1.length; int n = nums2.length; int leftNum = (m + n) / 2; // 左边一半数字的个数 // 如果 m + n 是偶数 则左边应该有6个数 ,最终结果就是左边一半的最大值加上右边一半的最小值 再除以2 // 如果 m + n 是奇数 则左边应该有5个数, 最终结果就是右边一半的最小值 int L = 0, R = m; // L 与 R 来逼近nums1数组的左右一半的分界线 while (L < R) { int i = (L + R + 1) / 2; // i的范围为[1,m] 代表nums1中属于左边一般的数字有i个 int j = leftNum - i; // 代表nums2中属于左边一半的数字有j个 if (nums1[i - 1] > nums2[j]) // 如果nums1左边数字的最大值还大于nums2右边数字的最小值 R--; else L++; // 如果nums1左边数字的最大值不大于nums2右边数字的最小值 } int num1Line = L; // 代表nums1中属于左边一般的数字有num1Line 个 int num2Line = leftNum - L; // 代表nums2中属于左边一般的数字有num2Line 个 if ((m + n) % 2 == 0){ int left = Math.max( num1Line == 0 ? Integer.MIN_VALUE : nums1[num1Line-1], num2Line == 0 ? Integer.MIN_VALUE : nums2[num2Line-1] ); int right = Math.min( num1Line == m ? Integer.MAX_VALUE : nums1[num1Line], num2Line == n ? Integer.MAX_VALUE : nums2[num2Line] ); return (left + right + 0.0) / 2; }else{ return Math.min( num1Line == m ? Integer.MAX_VALUE : nums1[num1Line], num2Line == n ? Integer.MAX_VALUE : nums2[num2Line] ); } } }
    Processed: 0.011, SQL: 8