二分查找--寻找两个有序数组的中位数

  力扣—寻找两个有序数组的中位数,下面看一下题目

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

示例 1:
nums1 = [1, 3]
nums2 = [2]
则中位数是 2.0
示例 2:
nums1 = [1, 2]
nums2 = [3, 4]
则中位数是 (2 + 3)/2 = 2.5

 给出代码:

class Solution {
public:
	//寻找2个数组中第k小的数,注意是2个数组, k = 7
    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();  //4
        int n = nums2.size();  //9
        int index1 = 0, index2 = 0;

        while (true) {
            // 边界情况
            //num1数组为空
            if (index1 == m) {
                return nums2[index2 + k - 1];
            }
			//num2数组为空
            if (index2 == n) {
                return nums1[index1 + k - 1];
            }

			//两个数组总共2个元素
            if (k == 1) {
                return min(nums1[index1], nums2[index2]);
            }
			

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

    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;
        }
    }
};

看到上面的解释挺多的,只看也看不出啥,还是自己推敲一遍。例如有如下2个数组

num1: 1 3 4 9

num2: 1 2 3 4 5 6 7 8 9

总和为13,则k=7

m = 4,n = 9,index1=0,index2=0

newIndex1= min(0+7/2-1,4-1) = 2,newIndex2 = min(0+7/2-1,9) = 2(newIndex1相当于调位之后的下标,index1是递增的下标)

pivot1=num1[2]  =4   , pivot2=num2[2]=3

4 > 3 , k -= 2-0+1 =  4 , index2 = 2 + 1 = 3(此时num1[2]是第6小的,但现在要找第7小的,只需要找到比num1[2]大1个的)

//—————————————————————-

newIndex1 = min(0+4/2-1,4-1) = 1 , newIndex2 = min(3+4/2-1,9) = 4(这里num2一下跳了2个位,因为是根据k值进行二分,不用每次跳一个位,这样减少遍历个数)

pivot1 = num1[1] = 3 , pivot2 = num2[4] = 5

3 < 5  , k-=1-0+1=2 , index1 = 2

//————————————————

newIndex1  = min(2+2/2-1,4-1) = 2 ,  newIndex2 = min(3+2/2-1,9) = 3

pivot1 = num1[4] = 3 , pivot2 = num2[3] = 4

4 == 4 ,k-=2-2+1=1 ,然后取个4,k=0,则找到了。题目用k/2进行二分查找,根据k/2选择跳位比较,然后在慢慢缩小范围。

 

参考地址:https://leetcode-cn.com/problems/median-of-two-sorted-arrays/solution/xun-zhao-liang-ge-you-xu-shu-zu-de-zhong-wei-s-114/

 

    原文作者:盼盼编程
    原文地址: https://blog.csdn.net/ma2595162349/article/details/108090281
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞