ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

4.寻找两个有序数组的中位数

2022-08-14 16:32:04  阅读:125  来源: 互联网

标签:totalLength frac 数组 中位数 有序 nums1 nums2


首先这个题目最容易想到的解决方法是把两个数组合并之后选出中位数,但是这样的时间复杂度为\(O(m+n)\)与题目的要求不符合,根据题目中的要求\(O(log(m+n))\)可以想到可能要采取二分的手段进行中位数的寻找,所以考虑不把两个数组合并,而是直接寻找中位数。

通过中位数的概念可知,对一个总长度为N的数组,其中位数要么在\(\frac{N}{2}\),要么是\(\frac{N}{2}\)与\(\frac{N+1}{2}\)的均值。这样可以把原题转换为寻找两个数组中第k小的数。

每一次寻找都进行二分查找,比较\(A[\frac{k}{2}]\)与\(B[\frac{k}{2}]\),如下图所示,
image
通过比较的结果可以进行分类讨论:

  • 如果\(A[\frac{k}{2}]\)小于等于\(B[\frac{k}{2}]\),则从\(A[1]\)到\(A[\frac{k}{2}]\)的数均不可能为我们所要寻找的数,则可以将这\(\frac{k}{2}\)个数排除,再进行后续操作
  • 如果\(A[\frac{k}{2}]\)大于\(B[\frac{k}{2}]\),则从\(B[1]\)到B[\frac{k}{2}]\(的数均不可能为我们所要寻找的数,则可以将这\)\frac{k}{2}$个数排除,再进行后续操作

之后重复上述过程即可,但是在上述通用过程中可能出现一些特殊情况:

  • 如果\(A[\frac{k}{2}]\)与\(B[\frac{k}{2}]\)越界,则可以选取对应数组的最后一个元素进行比较;
  • 如果一个数组为空则直接返回另一个数组的第k个元素;
  • 如果k=1直接返回两个数组中第一个元素中更小的元素。

官方代码:

class Solution {
public:
    int getKthElement(const vector<int>& nums1, const vector<int>& nums2, int k) {
        /* 主要思路:要找到第 k (k>1) 小的元素,那么就取 pivot1 = nums1[k/2-1] 和 pivot2 = nums2[k/2-1] 进行比较
         * 这里的 "/" 表示整除
         * nums1 中小于等于 pivot1 的元素有 nums1[0 .. k/2-2] 共计 k/2-1 个
         * nums2 中小于等于 pivot2 的元素有 nums2[0 .. k/2-2] 共计 k/2-1 个
         * 取 pivot = min(pivot1, pivot2),两个数组中小于等于 pivot 的元素共计不会超过 (k/2-1) + (k/2-1) <= k-2 个
         * 这样 pivot 本身最大也只能是第 k-1 小的元素
         * 如果 pivot = pivot1,那么 nums1[0 .. k/2-1] 都不可能是第 k 小的元素。把这些元素全部 "删除",剩下的作为新的 nums1 数组
         * 如果 pivot = pivot2,那么 nums2[0 .. k/2-1] 都不可能是第 k 小的元素。把这些元素全部 "删除",剩下的作为新的 nums2 数组
         * 由于我们 "删除" 了一些元素(这些元素都比第 k 小的元素要小),因此需要修改 k 的值,减去删除的数的个数
         */

        int m = nums1.size();
        int n = nums2.size();
        int index1 = 0, index2 = 0;

        while (true) {
            // 边界情况
            if (index1 == m) {
                return nums2[index2 + k - 1];
            }
            if (index2 == n) {
                return nums1[index1 + k - 1];
            }
            if (k == 1) {
                return min(nums1[index1], nums2[index2]);
            }

            // 正常情况
            int newIndex1 = min(index1 + k / 2 - 1, m - 1);
            int newIndex2 = min(index2 + k / 2 - 1, n - 1);
            int pivot1 = nums1[newIndex1];
            int pivot2 = nums2[newIndex2];
            if (pivot1 <= pivot2) {
                k -= newIndex1 - index1 + 1;
                index1 = newIndex1 + 1;
            }
            else {
                k -= newIndex2 - index2 + 1;
                index2 = newIndex2 + 1;
            }
        }
    }

    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int totalLength = nums1.size() + nums2.size();
        if (totalLength % 2 == 1) {
            return getKthElement(nums1, nums2, (totalLength + 1) / 2);
        }
        else {
            return (getKthElement(nums1, nums2, totalLength / 2) + getKthElement(nums1, nums2, totalLength / 2 + 1)) / 2.0;
        }
    }
};

标签:totalLength,frac,数组,中位数,有序,nums1,nums2
来源: https://www.cnblogs.com/LYX-Blogs/p/16585666.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有