首页 > 其他分享 >寻找两个正序数组的中位数

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

时间:2023-03-10 20:57:38浏览次数:41  
标签:正序 int 中位数 len1 数组 nums1 nums2

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

给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。

算法的时间复杂度应该为 O(log (m+n)) 。

 

示例 1:

输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2

示例 2:

输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5

方法一
基本思路:归并排序,即将两个有序的数组归并成一个更大的有序数组。要将一个数组排序,可以先递归将它分成两个有序数组,然后将结果归并。
优点:实现简单,逻辑简单,类似对一个更大的数组重新排序
缺点:需要一个额外的空间,空间复杂度高
int main()
{
    int nums1[] = {1,2,4,9};
    int nums2[] = {1,2,3,4,5,6,7,8,9,10};
    int nums1Size = 4, nums2Size = 10;      //测试数组

    float mid = 0;
    int left = 0, right = nums1Size;      //左右两个有序数组
    int len = nums1Size + nums2Size;      
    int *aux = malloc(sizeof(int) * len);  //辅助数组,用于存储两个有序数组
    int *result = malloc(sizeof(int) * len); //保存归并结果

    for(int i = 0; i < nums1Size; i++)    //装入辅助数组
    {
        aux[i] = nums1[i];
    }

    for(int j = nums1Size , m = 0; j < len; j++, m++)
    {
        aux[j] = nums2[m];
    }

  /*
  进行归并
  进行4个判断条件
  左半边数组耗尽
  右半边数组耗尽
  右半边的当前数组小于左半边数组元素
  右半边的当前数组元素大于或等于左半边数组元素
              */ for(int k = 0; k < len; k++)      { if(left > nums1Size - 1) result[k] = aux[right++]; else if(right > len) result[k] = aux[left++]; else if(aux[right] < aux[left]) result[k] = aux[right++]; else result[k] = aux[left++]; } mid = len%2 == 0 ? (result[len/2] + result[len/2 - 1])/2.0 : result[len/2];return 0; }

 程序可以正常在Code::Block上运行,但无法通过leetcode编译(不懂)

方法二

基本思路:二分查找

根据中位数的定义,对于两个有序数组,若m+n为奇数, 中位数是第(m+n)/2个数;若m+n为偶数,中位数为第(m+n)/2 与第(m+n)/2 -1个数的平均值

因此,这道题可以转化成寻找两个有序数组中的第 k 小的数

其实在两个有序数组中,寻找中位数并不需要每一个元素都遍历到。

根据有序数组的性质,可以假设中位数为第k小的数,那么对于比第k/2小的数,其实就可以直接排除了

更一般的情况 A[1] ,A[2] ,A[3],A[k/2] ... ,B[1],B[2],B[3],B[k/2] ... ,如果 A[k/2]<B[k/2] ,那么A[1],A[2],A[3],A[k/2]都不可能是第 k 小的数字。

A 数组中比 A[k/2] 小的数有 k/2-1 个,B 数组中,B[k/2] 比 B[k/2] 小的数同样有k/2-1,假设 B[k/2] 前边的数字都比 A[k/2] 小,也只有 k/2-1 个,所以比 A[k/2] 小的数字最多有 k/1-1+k/2-1=k-2个,所以 A[k/2] 最多是第 k-1 小的数。而比 A[k/2] 小的数更不可能是第 k 小的数了,所以可以把它们排除。

因此,可以归纳出以下几点

  • 若A[k/2-1]<B[k/2-1], 则A[0]~A[k/2-1]的元素都可以排除
  • 若A[k/2-1]>B[k/2-1],则B[0]~B[k/2-1]的元素都可以排除
  • 若相等,当做第一种情况处理
  • 若k/2>len_A(数组A的长度),毫无疑问,第k小的数,只能在数组B中

采用递归实现

double findMedianSortedArrays(int* nums1, int nums1Size, int* nums2, int nums2Size){
    int len1 = nums1Size ,len2 = nums2Size;
    int left = (len1 + len2 + 1)/2;
    int right = (len1 + len2 + 2)/2;
  //若为奇数,重复计算2遍;若为偶数,直接出结果
    return (getKth(nums1, 0, len1 - 1, nums2, 0, len2 - 1, left) + getKth(nums1, 0, len1 - 1, nums2, 0, len2 - 1, right))*0.5;

}

int getKth(int *nums1, int start1, int end1, int *nums2, int start2, int end2, int k)
{
    int len1 = end1 - start1 + 1;
    int len2 = end2 - start2 + 1;

    if(len1 > len2)          //确保len1的长度总为最短的,方便计算
        getKth(nums2, 0, len2 - 2, nums1, 0, len1 - 1,  k);
    if(len1 == 0)            //特殊情况的处理
        return nums2[start2 + k - 1];
    if(k == 1)
        return nums1[start1] < nums2[start2] ? nums1[start1] : nums2[start2];

    int min1 = (len1 < k/2) ? len1 : k/2;
    int min2 = (len2 < k/2) ? len2 : k/2;

    int i = start1 + min1 - 1;      //可以当成指针一样理解,操控指针移动
    int j = start2 + min2 - 1;
    if(nums1[i] > nums2[j])      //排除一次,更新第k小的数
    {
        return getKth(nums1 , start1, end1, nums2, j+1, end2, k - (j - start2 + 1));
    }
    else
    {
        return getKth(nums1, i+1, end1, nums2, start2, end2, k - (i - start1 + 1));
    }

            
}

程序可以正常在Code::Block上运行,但无法通过leetcode编译(不懂)

 

附:

 

 



标签:正序,int,中位数,len1,数组,nums1,nums2
From: https://www.cnblogs.com/hk-to-try/p/17204567.html

相关文章

  • ES6-ES11 ES10数组方法扩展-flat与flatMap
    原视频<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,initial-scale=1.0"><title......
  • java-IO-字节流读数据(一次读一个字节数组数据)
         ......
  • java学习日记20230310-数组
    数组数组/排序/查找数组可以存放多个统一类型的数据,数组本身也是一种数据类型,引用类型;    array.length标识数组的大小/长度数组的定义数据类型[]数组名......
  • numpy数组中根据判定条件提取索引位置
    要求:我有两个numpy类型的数组,第一个维度都是相同的,其中一个数组中都是0或者1,如果是1,则将两一个数组中的相同位置提取出来形成一个新的numpy数组可以使用numpy的boolean......
  • java自定义类数组的初始化
    也就是说,在声明了自定义类的数组之后,对每一个数组元素的初始化,都要为其new一个对象出来使得指针指向该对象,Java语言本身是不提供在自定义类数组声明时候自动创建新对象的方......
  • C++ 数组 指针小记
    voidfun(int*aa){return;}int*a=newint[16];memset(a,0,16);fun(a);voidfun(int*aa){return;}inta[16]={0};fun(a);  总之,两......
  • C# 对一维数组进行分组,每组固定数量
    效果:[1,2,3,4,5,6]拆分为每个数组内2个数字[[1,2],[3,4],[5,6]]///<summary>///根据数量对数组进行分组///</summary>///<paramname="list"></param>///<pa......
  • spring学习48-属性注入注入数组和列表的说明
    pom.xml<?xmlversion="1.0"encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchem......
  • 数组的方法之遍历篇
    forEach()//Array.prototype.forEach()方法对每个元素执行一次提供的回调函数;//第一个参数是我们提供的回调函数;//第二个参数thisArg:回调函数中this指向,即如果我们想......
  • 数组和哈希表的选择
    使用数组来做哈希的题目,是因为题目都限制了数值的大小。题目没有限制数值的大小,就无法使用数组来做哈希表了。而且如果哈希值比较少、特别分散、跨度非常大,使用数组就造......