leetcode刷题记录-寻找两个正序数组的中位数

leetcode刷题记录

题目 寻找两个正序数组的中位数

题目描述

思路

算法模型:
在两个都有序的数组中找上中位数

题意
O(logN)

题解

分情况
偶数个数的时候, 二分

  1. 2==2’ 这里的2是表示 位置
    在这里插入图片描述

  2. 2>2’ 看谁不会再有机会成为第四小

  3. 2<2’
    在这里插入图片描述

[1 2] 和 [3’ 4’]把它理解为是两个等长的有序数组,求它俩整体四个数的第二小,
就是最大的整体的第四小。
递归下去
这4个数不管是谁成为了后续过程中的上中位数,它都是整体的上中位数
在这里插入图片描述

奇数个数的时候

  1. 3==3’
    在这里插入图片描述

  2. 3>3’
    上面[1, 2] 下面[3’ , 4’, 5’]不等长, 没有办法递归下去
    单独验证3’
    如果发现自己大于等于2,但又没干过3,你直接返回
    如果你发现这个不成立多淘汰掉一个,剩下4’5’跟着上面[1, 2]玩递归

  3. 3<3’

在这里插入图片描述

代码

// A[s1...e1]
	// B[s2...e2]
	// 一定等长!
	// 返回整体的,上中位数!8(4) 10(5) 12(6)
	public static int getUpMedian(int[] A, int s1, int e1, int[] B, int s2, int e2) {
		int mid1 = 0;
		int mid2 = 0;
		while (s1 < e1) {
			// mid1 = s1 + (e1 - s1) >> 1
			mid1 = (s1 + e1) / 2;
			mid2 = (s2 + e2) / 2;
			if (A[mid1] == B[mid2]) {
				return A[mid1];
			}
			// 两个中点一定不等!
			if (((e1 - s1 + 1) & 1) == 1) { // 奇数长度
				if (A[mid1] > B[mid2]) {
					if (B[mid2] >= A[mid1 - 1]) {  //相当于上面说的 3' 没干过 3 但是干过了2  3'就是第 5 小 直接返回
						return B[mid2];
					}
					e1 = mid1 - 1;
					s2 = mid2 + 1;
				} else { // A[mid1] < B[mid2]
					if (A[mid1] >= B[mid2 - 1]) {  //同理
						return A[mid1];
					}
					e2 = mid2 - 1;
					s1 = mid1 + 1;
				}
			} else { // 偶数长度
				if (A[mid1] > B[mid2]) {
					e1 = mid1;
					s2 = mid2 + 1;
				} else {
					e2 = mid2;
					s1 = mid1 + 1;
				}
			}
		}
		return Math.min(A[s1], B[s2]);
	}

进阶:
在两个都有序的数组中找整体第K小的数
进阶问题: 在两个都有序的数组中找整体第K小的数 可以做到O(log(Min(M,N)))

题意
O(log min(M, N))

k的范围1~27

题解
分段讨论

  1. 1<= k <=短数组长度
    两个 等长数组求上中位数
    在这里插入图片描述

边界也对
在这里插入图片描述

  1. 长数组长度 < k <= 整体长度
    在这里插入图片描述

手动验证13跟10’, 6’跟17
你可以通过具体的arr1, arr2的长度跟 K 的值换算出哪个部分是不可能的,哪个部分是单独验证的。
在这里插入图片描述

边界情况也是对的
在这里插入图片描述

  1. 短数组长度<k <= 长数组长度
    短数组全有可能
    在这里插入图片描述

从5~15是 11 个数,1’~10’是10个数不等长没法用算法原型
手动淘汰5 验5跟10’
在这里插入图片描述

为什么手动淘汰5, 而不是15
在这里插入图片描述

手动淘汰的目的是一方面是我要接下来调的算法原型要等长,不然的话我不知道他对不对,
或者说我们只实现了等常情况下上中位数的原型,这是第1个目的,第2个目的就是让我淘汰掉的树和出来的数正好能凑够那个位置

复杂度
拿等长两段二分, 所以要拿短数组的长度为主

在这里插入图片描述

	// 进阶问题 : 在两个都有序的数组中,找整体第K小的数
	// 可以做到O(log(Min(M,N)))
	public static int findKthNum(int[] arr1, int[] arr2, int kth) {
		int[] longs = arr1.length >= arr2.length ? arr1 : arr2;
		int[] shorts = arr1.length < arr2.length ? arr1 : arr2;
		int l = longs.length;
		int s = shorts.length;
		if (kth <= s) { // 1)
			return getUpMedian(shorts, 0, kth - 1, longs, 0, kth - 1);
		}
		if (kth > l) { // 3)
			if (shorts[kth - l - 1] >= longs[l - 1]) {
				return shorts[kth - l - 1];
			}
			if (longs[kth - s - 1] >= shorts[s - 1]) {
				return longs[kth - s - 1];
			}
			return getUpMedian(shorts, kth - l, s - 1, longs, kth - s, l - 1);
		}
		// 2)  s < k <= l
		if (longs[kth - s - 1] >= shorts[s - 1]) {  //就是例子中的手动淘汰 5 
			return longs[kth - s - 1];
		}
		return getUpMedian(shorts, 0, s - 1, longs, kth - s, kth - 1);
	}

LeetCode
4.寻找两个正序数组的中位数 [H]
最多就掉两回 findKthNum 加起来再除二

    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int size = nums1.length + nums2.length;
        boolean even = (size & 1) == 0;
        if (nums1.length != 0 && nums2.length != 0) {
            if (even) {
                return (double) (findKthNum(nums1, nums2, size / 2) + findKthNum(nums1, nums2, size / 2 + 1)) / 2D;
            } else {
                return findKthNum(nums1, nums2, size / 2 + 1);
            }
        } else if (nums1.length != 0) {
            if (even) {
                return (double) (nums1[(size - 1) / 2] + nums1[size / 2]) / 2;
            } else {
                return nums1[size / 2];
            }
        } else if (nums2.length != 0) {
            if (even) {
                return (double) (nums2[(size - 1) / 2] + nums2[size / 2]) / 2;
            } else {
                return nums2[size / 2];
            }
        } else {
            return 0;
        }
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值