zoukankan      html  css  js  c++  java
  • [LeetCode] 4. 寻找两个有序数组的中位数

    传送门:[LeetCode] 4. 寻找两个有序数组的中位数

    题目描述

    给定两个大小为 m 和 n 的有序数组 nums1nums2

    请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 (O(log(m + n)))

    你可以假设 nums1nums2 不会同时为空。

    示例 1:

    nums1 = [1, 3]
    nums2 = [2]

    则中位数是 2.0

    示例 2:

    nums1 = [1, 2]
    nums2 = [3, 4]

    则中位数是 (2 + 3)/2 = 2.5

    分析与代码

    • 首先两个有序数组,合并后就得到一个有序数组,相当于归并排序的最后一步,然后判断数组长度,奇数返回中间值,偶数返回中间两个数的平均值。但是,合并两个数组所需时间复杂度为 O(m + n),题目要求时间复杂度为 O(log(m + n)),log 复杂度就想到二分算法了。
    • 换种思路,求中位数,数组长度为奇数时其实就是求第 k 小的数(k 为中间那个数,从1数起),偶数时就是求第 k 小的数和第 k+1 小的数的平均值。
    • 我们每次遍历时,比较两个数组中的第 k/2 个数字,如果哪个小,就表明该数组的前 k/2 个数字都不会是第 k 小的数字,可以直接排除掉。但是注意,若数组的长度不足 k/2,就取数组最后一个数去访问比较判断。
    • 接下来就是重复第 3 步,但 k 要减去排除的数字的个数,直到k == 1,或者有一个数组为空。
    • 若以k == 1结束,返回两个数组的第一个数中较小值;若有一个数组为空,返回另一个数组中的第 k 个数。

    代码:

    class Solution {
        public double findMedianSortedArrays(int[] nums1, int[] nums2) {
            int n = nums1.length;
            int m = nums2.length;
            if (((m + n) & 1) == 1) {
                return getKth(nums1, 0, nums2, 0, (n + m + 1) / 2);
            } else {
                return (getKth(nums1, 0, nums2, 0, (n + m + 1) / 2)
                        + getKth(nums1, 0, nums2, 0, (n + m + 2) / 2)) / 2.0;
            }
        }
    
        public int getKth(int[] nums1, int start1, int[] nums2, int start2, int k) {
            int len1 = nums1.length - start1;
            int len2 = nums2.length - start2;
            if (len1 == 0) {
                return nums2[start2 + k - 1];
            }
            if (len2 == 0) {
                return nums1[start1 + k - 1];
            }
            if (k == 1) {
                return Math.min(nums1[start1], nums2[start2]);
            }
            int i = start1 + Math.min(len1, k / 2) - 1;
            int j = start2 + Math.min(len2, k / 2) - 1;
            if (nums1[i] > nums2[j]) {
                return getKth(nums1, start1, nums2, j + 1, k - (j - start2 + 1));
            } else {
                return getKth(nums1, i + 1, nums2, start2, k - (i - start1 + 1));
            }
        }
    }
    

    小结

    这题的二分是对 k 进行二分,每次能排除 k/2 个数。

    在一个数组里二分简单,在这题里学习在两个数组里进行二分。



    ┆ 然 ┆   ┆   ┆   ┆ 可 ┆   ┆   ┆ 等 ┆ 暖 ┆
    ┆ 而 ┆ 始 ┆   ┆   ┆ 是 ┆ 将 ┆   ┆ 你 ┆ 一 ┆
    ┆ 你 ┆ 终 ┆ 大 ┆   ┆ 我 ┆ 来 ┆   ┆ 如 ┆ 暖 ┆
    ┆ 没 ┆ 没 ┆ 雁 ┆   ┆ 在 ┆ 也 ┆   ┆ 试 ┆ 这 ┆
    ┆ 有 ┆ 有 ┆ 也 ┆   ┆ 这 ┆ 会 ┆   ┆ 探 ┆ 生 ┆
    ┆ 来 ┆ 来 ┆ 没 ┆   ┆ 里 ┆ 在 ┆   ┆ 般 ┆ 之 ┆
    ┆   ┆   ┆ 有 ┆   ┆   ┆ 这 ┆   ┆ 降 ┆ 凉 ┆
    ┆   ┆   ┆ 来 ┆   ┆   ┆ 里 ┆   ┆ 临 ┆ 薄 ┆
  • 相关阅读:
    HDU 1010 Tempter of the Bone
    HDU 4421 Bit Magic(奇葩式解法)
    HDU 2614 Beat 深搜DFS
    HDU 1495 非常可乐 BFS 搜索
    Road to Cinema
    Sea Battle
    Interview with Oleg
    Spotlights
    Substring
    Dominating Patterns
  • 原文地址:https://www.cnblogs.com/qiu_jiaqi/p/LeetCode-4.html
Copyright © 2011-2022 走看看