寻找两个正序数组的中位数-二分查找4-python&c++

python

一. 无脑傻瓜版本:

没看答案

1.把两个数组合并成一个数组并排序;
2.找到新数组的中位数。

class Solution:
    def findMedianSortedArrays(self, nums1, nums2):
        ls = list()
        for i in nums1:
            ls.append(i)
        for j in nums2:
            ls.append(j)
        
        ls.sort()
        num = len(ls)
        a = 0
        if num % 2 == 0:
            a = (ls[num//2-1] + ls[num//2])/2
        else:
            a = ls[num//2]
        return a

复杂度分析:

  • 时间复杂度和空间复杂度都是O(m+n)。

二. 二分查找:

主要思路:

  • 要找到第 k (k>1) 小的元素,那么就取 prior1 = nums1[k//2-1] 和 prior2 = nums2[k//2-1] 进行比较;

  • nums1 中小于等于 prior1 的元素有 nums1[0 … k//2-2] 共计 k//2-1 个,nums2 中小于等于 prior2 的元素有 nums2[0 … k//2-2] 共计 k//2-1 个;

  • 取 prior = min(prior1, prior2),两个数组中小于等于 prior 的元素共计不会超过 (k//2-1) + (k//2-1) ≤ k-2 个,这样 prior 本身最大也只能是第 k-1 小的元素(即prior1=prior2的时候);

  • 如果 prior = prior1,那么 nums1[0 … k//2-1] 都不可能是第 k 小的元素。把这些元素全部"删除",剩下的作为新的 nums1 数组(即指针移动到k//2位置),如果 prior= prior2,那么 nums2[0 … k//2-1] 都不可能是第 k 小的元素,把这些元素全部 “删除”,剩下的作为新的 nums2 数组(即指针移动到k//2位置);

  • 由于我们 “删除” 了一些元素(这些元素都比第 k 小的元素要小),因此需要修改 k 的值,减去删除元素的个数。

class Solution:
    def findMedianSortedArrays(self, nums1, nums2):
        m, n = len(nums1), len(nums2)
        def getKthitem(k):
            index0, index1 = 0, 0 # nums1 和 nums2 的指针位置
            while True:
                if index0 == m:
                    return nums2[index1 + k - 1]
                if index1 == n:
                    return nums1[index0 + k - 1]
                if k == 1:
                    return min(nums1[index0], nums2[index1])
                
                newindex0 = min(index0 + k//2 - 1, m-1) # 二分查找,且防止越界
                newindex1 = min(index1 + k//2 - 1, n-1) # 二分查找,且防止越界
                prior1, prior2 = nums1[newindex0], nums2[newindex1]
                if prior1 <= prior2: # 一次只对一个数组进行操作
                    k -= newindex0 - index0 + 1 # k减去删除元素的个数
                    index0 = newindex0 + 1 # “删除”元素
                else:
                    k -= newindex1 - index1 + 1 # k减去删除元素的个数
                    index1 = newindex1 + 1 # “删除”元素

        totallength = m + n
        if totallength % 2 == 0:
            return (getKthitem(totallength//2) + getKthitem(totallength//2+1))/2
        else:
            return getKthitem(totallength//2+1)

复杂度分析:

  • 时间复杂度:O(log(m+n)),其中 m 和 n 分别是数组 nums1 和 nums2 的长度。
  • 空间复杂度:O(1)。

c++

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        // 可以将该问题转化为找出nums1+nums2的第k小的数
        // 由于要求对数时间复杂度,故考虑用二分查找思想,需要考虑如何在每次搜索后,都能排除一半的搜索空间
        // 考虑设定标定值为a=nums1[k/2-1]和b=nums2[k/2-1]:
        //    如果a小于等于b,则不大于a的数最多只有k/2-1 + k/2-1 = k-2个,算上a本身也最多是第k-1小的数,所以nums1[0:k/2-1]都可以排除了
        //    如果a大于b,同理可以排除nums2[0:k/2-1]
        //    每次排除后,k要减去排除的数字个数k/2,实现k的更新
        //    最终当k为1时,返回此时nums1和nums2剩余部分的最左侧元素中小的那个
        //    如果排除过程中某个数组无剩余了,则返回另一个数组剩余部分的此时第k个元素
        int length = nums1.size() + nums2.size();
        if (length % 2 == 1) {
            return get_kth_element(nums1, nums2, length / 2 + 1);
        } else {
            return (get_kth_element(nums1, nums2, length / 2) + get_kth_element(nums1, nums2, length / 2 + 1)) / 2.0;
        }
    }

    double get_kth_element(vector<int> nums1, vector<int> nums2, int k) {
        int m = nums1.size(), 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 curr_index1 = min(index1 + k/2-1, m-1);
            int curr_index2 = min(index2 + k/2-1, n-1);
            
            // k必须通过两个索引的差值进行更新,因为可能某个数组非常短,排除的元素可能小于k/2个
            if (nums1[curr_index1] <= nums2[curr_index2]) {
                k -= curr_index1 - index1 + 1;
                index1 = curr_index1 + 1;
            } else {
                k -= curr_index2 - index2 + 1;
                index2 = curr_index2 + 1;
            }
        }
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值