给定两个大小为 m 和 n 的有序数组 nums1 和 nums2 。

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

示例 1:

  1. nums1 = [1, 3]
  2. nums2 = [2]
  3.  
  4. 中位数是 2.0

示例 2:

  1. nums1 = [1, 2]
  2. nums2 = [3, 4]
  3.  
  4. 中位数是 (2 + 3)/2 = 2.5

自己的思路:既然两个数组都是有序的,我可以将两个数组合并成一个数组,依然有序,然后根据奇偶来判断出中位数。

  1. double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2)
  2. {
  3. vector<int>nums;
  4. int i=0,j=0;
  5. while(i<nums1.size() && j<nums2.size())
  6. {
  7. if(nums1[i]<nums2[j])
  8. {
  9. nums.push_back(nums1[i++]);
  10. }
  11. else
  12. {
  13. nums.push_back(nums2[j++]);
  14. }
  15. }
  16. if(i==nums1.size())
  17. {
  18. while(j<nums2.size())
  19. nums.push_back(nums2[j++]);
  20. }
  21. else if(j==nums2.size())
  22. {
  23. while(i<nums1.size())
  24. nums.push_back(nums1[i++]);
  25. }
  26. if(nums.size()%2)
  27. return nums[nums.size()/2];
  28. else
  29. {
  30. return (double)(nums[nums.size()/2]+nums[nums.size()/2-1])/2;
  31. }
  32. }

但是这个算法很明显的不符合题目中的算法复杂度的要求,所以整理了他人的优秀实现方法

(1)中位数,其实就是找到第k个大小的元素的特例。在单数组中实现方式简单,关键是如何在两个数组中找到第k大的元素。

难就难在要在两个未合并的有序数组之间使用二分法,这里我们需要定义一个函数来找到第K个元素,由于两个数组长度之和的奇偶不确定,因此需要分情况来讨论,对于奇数的情况,直接找到最中间的数即可,偶数的话需要求最中间两个数的平均值。下面重点来看如何实现找到第K个元素,首先我们需要让数组1的长度小于或等于数组2的长度,那么我们只需判断如果数组1的长度大于数组2的长度的话,交换两个数组即可,然后我们要判断小的数组是否为空,为空的话,直接在另一个数组找第K个即可。还有一种情况是当K = 1时,表示我们要找第一个元素,只要比较两个数组的第一个元素,返回较小的那个即可。

首先假设数组A和B的元素个数都大于k/2,我们比较A[k/2-1]和B[k/2-1]两个元素,这两个元素分别表示A的第k/2小的元素和B的第k/2小的元素。这两个元素比较共有三种情况:>、<和=。如果A[k/2-1]大于B[k/2-1],则A[k/2-1]小于合并之后的第k小值。

证明也很简单,可以采用反证法。假设A[k/2-1]大于合并之后的第k小值,我们不妨假定其为第(k+1)小值。由于A[k/2-1]小于B[k/2-1],所以B[k/2-1]至少是第(k+2)小值。但实际上,在A中至多存在k/2-1个元素小于A[k/2-1],B中也至多存在k/2-1个元素小于A[k/2-1],所以小于A[k/2-1]的元素个数至多有k/2+ k/2-2,小于k,这与A[k/2-1]是第(k+1)的数矛盾。

同理当A[k / 2 - 1] > B[k / 2 -1]时存在类似的结论

当A[k / 2 - 1] = B[k / 2 -1]时,表示,在在A的k/2 -1之前已经有k/2 -1和数小于A[k / 2 -1],同理在B 之前也是一样的,所以此时已经找到了第k小的数,即这个相等的元素。

  1. double findKth(vector<int> &nums1, int i, vector<int> &nums2, int j, int k)
  2. {
  3. // 首先需要让数组1的长度小于或等于数组2的长度
  4. if (nums1.size() - i > nums2.size() - j) {
  5. return findKth(nums2, j, nums1, i, k);
  6. }
  7. // 判断小的数组是否为空,为空的话,直接在另一个数组找第K个即可
  8. if (nums1.size() == i) {
  9. return nums2[j + k - 1];
  10. }
  11. // 当K = 1时,表示我们要找第一个元素,只要比较两个数组的第一个元素,返回较小的那个即可
  12. if (k == 1) {
  13. return min(nums1[i], nums2[j]);
  14. }
  15. int pa = min(i + k / 2, int(nums1.size())), pb = j + k - pa + i;
  16.  
  17. if (nums1[pa - 1] < nums2[pb - 1]) {
  18. return findKth(nums1, pa, nums2, j, k - pa + i);
  19. }
  20. else if (nums1[pa - 1] > nums2[pb - 1]) {
  21. return findKth(nums1, i, nums2, pb, k - pb + j);
  22. }
  23. else {
  24. return nums1[pa - 1];
  25. }
  26. }
  27. double findMedianSortedArrays(vector<int> A, vector<int> B) {
  28. int sizeA = A.size(), sizeB = B.size();
  29. if (sizeA <= 0 && sizeB <= 0) {
  30. return 0;
  31. }
  32. int total = sizeA + sizeB;
  33. if (total % 2 == 1) {
  34. return findKth(A, 0, B, 0, total / 2 + 1);
  35. }
  36. else {
  37. return (findKth(A, 0, B, 0, total / 2) + findKth(A, 0, B, 0, total / 2 + 1)) / 2;
  38. }
  39. }

这里比较难理解的点是判断(nums1[pa - 1] < nums2[pb - 1])之后执行了return findKth(nums1, pa, nums2, j, k - pa + i);其实这个操作是因为目前nums1的分界线的值小于nums2分界线的值,那么证明nums1分界线以及前面的值都小于合并后的第k的值,也就是中位数。那么我们可以从这里开始,继续寻找第k-(pa-i)的值,直到两个值相等为止。

(2)分治法。

https://hk029.gitbooks.io/leetbook/%E5%88%86%E6%B2%BB/004.%20Median%20of%20Two%20Sorted%20Arrays[H]/004.%20Median%20of%20Two%20Sorted%20Arrays[H].html

  1. double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
  2. if(nums1.size() == 0)
  3. return MedofArray(nums2);
  4. if(nums2.size() == 0)
  5. return MedofArray(nums1);
  6. int n = nums1.size();
  7. int m = nums2.size();
  8. if(n > m) //保证数组1一定最短
  9. return findMedianSortedArrays(nums2,nums1);
  10. int L1,L2,R1,R2,c1,c2,lo = 0, hi = 2*n; //我们目前是虚拟加了'#'所以数组1是2*n+1长度
  11. while(lo <= hi) //二分
  12. {
  13. c1 = (lo+hi)/2; //c1是二分的结果
  14. c2 = m+n- c1;
  15. L1 = (c1 == 0)?INT_MIN:nums1[(c1-1)/2]; //map to original element
  16. R1 = (c1 == 2*n)?INT_MAX:nums1[c1/2];
  17. L2 = (c2 == 0)?INT_MIN:nums2[(c2-1)/2];
  18. R2 = (c2 == 2*m)?INT_MAX:nums2[c2/2];
  19.  
  20. if(L1 > R2)
  21. hi = c1-1;
  22. else if(L2 > R1)
  23. lo = c1+1;
  24. else
  25. break;
  26. }
  27. return (max(L1,L2)+ min(R1,R2))/2.0;
  28. }
  29. double MedofArray(vector<int>& nums)
  30. {
  31. if(nums.size() == 0) return -1;
  32. return (nums[nums.size()/2]+nums[(nums.size()-1)/2])/2.0;
  33. }

需要细细思考下

Leetcode(4)-两个排序数组的中位数的更多相关文章

  1. LeetCode 4 - 两个排序数组的中位数 - [分治]

    题目链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays/description/ 给定两个大小为 m 和 n 的有序数组 n ...

  2. LeetCode#5 两个排序数组的中位数

      给定两个大小为 m 和 n 的有序数组 nums1 和 nums2 . 请找出这两个有序数组的中位数.要求算法的时间复杂度为 O(log (m+n)) . 你可以假设 nums1 和 nums2  ...

  3. leetcode 4.两个排序数组的中位数

    题目: 给定两个大小为 m 和 n 的有序数组 nums1 和 nums2 . 请找出这两个有序数组的中位数.要求算法的时间复杂度为 O(log (m+n)) . 你可以假设 nums1 和 nums ...

  4. leetcode,两个排序数组的中位数

    先上题目描述: 给定两个大小为 m 和 n 的有序数组 nums1 和 nums2 . 请找出这两个有序数组的中位数.要求算法的时间复杂度为 O(log (m+n)) . 你可以假设 nums1 和  ...

  5. leetcode python两个排序数组的中位数

    给定两个大小为 m 和 n 的有序数组 nums1 和 nums2 . 请找出这两个有序数组的中位数.要求算法的时间复杂度为 O(log (m+n)) . 你可以假设 nums1 和 nums2 不同 ...

  6. LeetCode(4):两个排序数组的中位数

    Hard! 题目描述: 有两个大小为 m 和 n 的排序数组 nums1 和 nums2 . 请找出两个排序数组的中位数并且总的运行时间复杂度为 O(log (m+n)) . 示例 1: nums1 ...

  7. LeetCode4. 两个排序数组的中位数

    4. 两个排序数组的中位数 问题描述 There are two sorted arrays nums1 and nums2 of size m and n respectively.Find the ...

  8. 2.Median of Two Sorted Arrays (两个排序数组的中位数)

    要求:Median of Two Sorted Arrays (求两个排序数组的中位数) 分析:1. 两个数组含有的数字总数为偶数或奇数两种情况.2. 有数组可能为空. 解决方法: 1.排序法 时间复 ...

  9. LeetCode-4. 两个排序数组的中位数(详解)

    链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays/description/ 有两个大小为 m 和 n 的排序数组 nums ...

  10. JavaScript实现获取两个排序数组的中位数算法示例

    本文实例讲述了JavaScript排序代码实现获取两个排序数组的中位数算法.分享给大家供大家参考,具体如下: 题目 给定两个大小为 m 和 n 的有序数组 nums1 和 nums2 . 请找出这两个 ...

随机推荐

  1. FI_F4_ZTERM付款条件代码

    这个函数可以弹出一个选择帮助,返回一个付款条件代码 CALL FUNCTION 'FI_F4_ZTERM' EXPORTING I_KOART = 'K' " K为供应商,D为客户 * I_ ...

  2. 技术基础 | Apache Cassandra 4.0基准测试

    Apache Cassandra 4.0已经发布了Beta版,这是第一个支持JDK 11及更高JDK版本的Cassandra版本.   时延对于Apache Cassandra用户来说是个显而易见的关 ...

  3. /bin/sh: cc: command not found

    make的时候报错:/bin/sh: cc: command not found 解决: 1. sudo yum -y install gcc gcc-c++ libstdc++-devel 2. m ...

  4. Docker部署SayHello(FastAPI)

    目录 前言 服务部署 部署后端 1. 进入到sayhello目录 2. 编写API的Dockerfile(如果有请之直接构建镜像- 在下一步) 3. 构建镜像 4. 运行容器 5. 访问IP:8000 ...

  5. maven打包三种方式

    https://blog.csdn.net/w820896059/article/details/80423143

  6. 指令集架构 x86-64 x86架构的64位拓展,向后兼容于16位及32位的x86架构

    https://zh.wikipedia.org/wiki/X86 x86泛指一系列英特尔公司用于开发处理器的指令集架构,这类处理器最早为1978年面市的"Intel 8086"C ...

  7. 【进阶】ZooKeeper 相关概念总结

    1. 开卷有益 学习是一种习惯,只有把这种习惯保持下来,每天不学习一点就感觉浑身不自在,达到这样的境界,那么你成为大佬也就不远了买,正如我们标题所写的"开卷有益".人生匆匆,要想过 ...

  8. 算法总结篇---KMP算法

    目录 写在前面 例题 剪花布条 Radio Transmission OKR-Periods of Words 似乎在梦中见过的样子 Censoring 写在前面 仅为自用,不做推广 一起来看猫片吧! ...

  9. HttpURLConnection下载文件流

    package com.loan.modules; import sun.net.www.protocol.file.Handler; import java.io.*; import java.ne ...

  10. 数理统计5:指数分布的参数估计,Gamma分布,Gamma分布与其他分布的联系

    今天的主角是指数分布,由此导出\(\Gamma\)分布,同样,读者应尝试一边阅读,一边独立推导出本文的结论.由于本系列为我独自完成的,缺少审阅,如果有任何错误,欢迎在评论区中指出,谢谢! 目录 Par ...