在两个长度相等的排序数组中找到上中位数

在两个长度相等的排序数组中找到上中位数

题目描述

给定两个有序数组arr1和arr2,已知两个数组的长度都为N,求两个数组中所有数的上中位数。

上中位数:假设递增序列长度为n,若n为奇数,则上中位数为第n/2+1个数;否则为第n个数

[要求]

时间复杂度为 O ( l o g N ) O(logN) O(logN),额外空间复杂度为 O ( 1 ) O(1) O(1)

输入描述:

第一行一个整数N,表示数组大小。
接下来一行N个整数,表示arr1内的元素
再接下来一行N个整数,表示arr内的元素

输出描述:

输出一个整数表示答案

示例1
输入
4
1 2 3 4
3 4 5 6
输出
3
说明
总共有8个数,上中位数是第4小的数,所以返回3。
示例2
输入
3
0 1 2
3 4 5
输出
2
说明
总共有6个数,那么上中位数是第3小的数,所以返回2
备注:

1 ⩽ N ⩽ 1 0 5 1 \leqslant N \leqslant 10^5 1N105
0 ⩽ a r r 1 i , a r r 2 i ⩽ 1 0 9 0 \leqslant arr_{1_{i}}, arr_{2_{i}} \leqslant 10^9 0arr1i,arr2i109


题解:

首先可以确定是二分,我们重新定义一下问题:在 a1[s1…e1] 和 a2[s2…e2] 上寻找两段数组的上中位数,并且两段数组长度相等。

  • 若每个数组只有一个元素,较小的那个就是整体的上中位数,相等的话,随便返回哪一个都行;

  • 若数组中不止一个元素,找到两个数组的中间位置 mid1 和 mid2 ,分情况讨论:

    1. 若 a1[mid1] == a2[mid2] ,无论数组元素个数是奇数还是偶数,这两个数都是整体的上中位数,返回其中一个即可
    2. 若 a1[mid1] > a2[mid2],分元素个数奇偶性讨论:
      • 若元素个数为奇数,a1 中 mid1 位置以后的元素都不可能是整体的上中位数,a2 中 mid2 位置以前的元素都不可能是整体的上中位数,所以只需要考虑 a1[s1…mid1] 和 a2[mid2…e2] ,两部分元素个数相同;
      • 若元素个数为偶数,a1 中 mid1 位置以后的元素都不可能是整体的上中位数, a2 中 mid2 位置以后包括 mid2 位置,都不可能是整体的上中位数,所以只需要考虑 a1[s1…mid1] 和 a2[mid2+1…e2] ,两部分元素个数相同
    3. 若 a1[mid1] < a2[mid2] ,分析同 2
代码:
#include <cstdio>
#include <algorithm>

using namespace std;

const int N = 100000;

int n;
int a[N];
int b[N];

int main(void) {
    scanf("%d", &n);
    for ( int i = 0; i < n; ++i )
        scanf("%d", a + i);
    for ( int i = 0; i < n; ++i )
        scanf("%d", b + i);
    if ( a[n - 1] <= b[0] || b[n - 1] <= a[0]) {
        printf("%d\n", min( a[n - 1], b[n - 1] ) );
        return 0;
    }
    int sa = 0, ea = n - 1;
    int sb = 0, eb = n - 1;
    int ma, mb, ret = -1;
    while ( sa < ea ) {
        ma = sa + ea >> 1;
        mb = sb + eb >> 1;
        if ( a[ma] == b[mb] ) {
            ret = a[ma];
            break;
        }
        int bit = ((ea - sa + 1) & 1) ^ 1;
        if ( a[ma] > b[mb] ) {
            ea = ma;
            sb = mb + bit;
        } else {
            eb = mb;
            sa = ma + bit;
        }
    }
    if ( ret == -1 ) ret = min( a[sa], b[sb] );
    printf("%d\n", ret);
    return 0;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 中位数是指将一个集合分为两个长度相等的子集,其一个子集的元素总是大于另一个子集的元素。对于给定两个正序数组,可以将它们合并成一个有序数组,然后找到这个有序数组中位数。 如果两个数组长度之和为奇数,中位数就是有序数组间的那个元素;如果长度之和为偶数,中位数就是有序数组两个元素的平均值。 具体实现可以使用归并排序的思想,将两个数组合并成一个有序数组,然后根据长度之和的奇偶性找到中位数。时间复杂度为 O(m+n)。 ### 回答2: 题目描述 给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2,请你找出并返回这两个正序数组中位数。 示例 示例1: 输入: nums1 = [1,3] nums2 = [2] 输出:2 示例2: 输入: nums1 = [1,2] nums2 = [3,4] 输出:2.5 解释: 合并数组后为 [1,2,3,4],中位数为 (2 + 3) / 2 = 2.5 解法 由于已知nums1和nums2都是正序,所以我们可以分别尝试对两个数组进行二分查找,找到两个数组中位数对应的位置。 首先,选定两个数组中位数的位置: - 对于一个长度为n的正序数组中位数的位置可以是n/2,也可以是(n-1)/2,因为n/2就是中位数所在的位置,但(n-1)/2和n/2的结果是一样的,因为这两个位置对应的两个数的差值对中位数的影响是一样的。 - 所以对于长度为m的nums1和长度为n的nums2,选定中位数的位置应该是(m+n+1)/2和(m+n+2)/2两个位置。 然后,我们对nums1进行二分查找,找到一个位置i,使得: nums1[i-1] <= nums2[j] && nums2[j-1] <= nums1[i] 我们可以将这个位置i称为“分割线”,分割线左边的元素可以组成一个长度为i+j-1的有序数组,右边的元素可以组成一个长度为m+n-i-j+1的有序数组。 对于奇数的情况,中位数就是分割线左边的元素和分割线右边的元素较大的那个。 对于偶数的情况,中位数就是分割线左边的元素和分割线右边的元素的平均数。 代码 ### 回答3: 首先,我们需要了解中位数的定义。中位数是一组数据居于间位置的数,即把一组数从小到大或从大到小排序后,位于间位置(如果有偶数个数,则取两个数的平均值)的数字。因此,要解这两个正序数组中位数,我们需要先将它们合并成一个有序数组,然后找出间位置的数或两个数的平均值。 合并两个有序数组的方法有很多种,这里介绍一种比较简单的方法:使用双指针法,分别指向两个数组的起始位置,逐个比较两个指针所指的数,将较小的数存入一个新数组中,并将指针后移,直到任意一个数组的数被取完,再将剩余的数组中的数依次存入新数组中。最终得到的新数组就是合并后的有序数组。 接下来,我们需要确定中位数的位置。假设两个有序数组长度分别为 m 和 n,那么它们的中位数要么是第 (m+n)/2 个数,要么是第 (m+n)/2 和 (m+n)/2+1 个数的平均值(当 m+n 为偶数时)。 因此,我们可以使用双指针法,同时遍历两个有序数组,记录已经遍历的数的个数,当遍历到第 (m+n)/2 或 (m+n)/2+1 个数时,就可以得到中位数。 下面是使用双指针法两个有序数组中位数的 Python 代码实现: ```python class Solution: def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float: m, n = len(nums1), len(nums2) nums = [] i, j = 0, 0 while i < m and j < n: if nums1[i] < nums2[j]: nums.append(nums1[i]) i += 1 else: nums.append(nums2[j]) j += 1 nums += nums1[i:] nums += nums2[j:] k = (m + n) // 2 if (m + n) % 2 == 0: return (nums[k-1] + nums[k]) / 2 else: return nums[k] ``` 该算法的时间复杂度为 O(m+n),空间复杂度为 O(m+n)。需要注意的是,由于 Python 整数除法运算会向下取整,因此计算中位数位置时需要使用 (m+n)//2 和 (m+n)//2+1。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值