关闭

有序数组中找中位数

104人阅读 评论(0) 收藏 举报

原文:Median of two sorted arrays

题目:两个有序数组A和B,大小都是n,寻找这两个数组合并后的中位数。时间复杂度为O(logn)。
中位数:如果数组的个数是奇数,那么中位数的值就是有序时处于中间的数;如果数组个数是偶数的,那么就是有序时中间两个数的平均值。

方法一:合并时计数

使用Merge Sort时的Merge操作,比较两个数组时候计数,当计数达到n时,就可以得到中位数,在归并的数组中,中位数为下标n-1和n的两个数的平均值。
时间复杂度O(n)。

#include <stdio.h>      
  
/*  
This function returns median of ar1[] and ar2[].     
Assumptions in this function:     
Both ar1[] and ar2[] are sorted arrays     
Both have n elements  
*/  
int getMedian(int ar1[], int ar2[], int n)   
{  
    int i = 0;  /* Current index of i/p array ar1[] */      
    int j = 0; /* Current index of i/p array ar2[] */      
    int count;       
    int m1 = -1, m2 = -1;        
   
    /* Since there are 2n elements, median will be average of elements at index n-1 and n  
    in the array obtained after merging ar1 and ar2 */      
    for (count = 0; count <= n; count++)       
    {           
        /*Below is to handle case where all elements of ar1[] are smaller than smallest(or first) element of ar2[]*/          
        if (i == n)           
        {               
            m1 = m2;               
            m2 = ar2[0];             
            break;         
        }           
        /*Below is to handle case where all elements of ar2[] are smaller than smallest(or first) element of ar1[]*/          
        else if (j == n)           
        {      
            m1 = m2;    
            m2 = ar1[0];    
            break;          
        }          
        if (ar1[i] < ar2[j])      
        {    
            m1 = m2;  /* Store the prev median */              
            m2 = ar1[i];               
            i++;          
        }          
        else         
        {            
            m1 = m2;  /* Store the prev median */            
            m2 = ar2[j];            
            j++;         
        }      
    }        
    return (m1 + m2)/2;   
}     
  
/* Driver program to test above function */  
int main()   
{      
    int ar1[] = {1, 12, 15, 26, 38};       
    int ar2[] = {2, 13, 17, 30, 45};        
    int n1 = sizeof(ar1)/sizeof(ar1[0]);      
    int n2 = sizeof(ar2)/sizeof(ar2[0]);      
    if (n1 == n2)         
        printf("Median is %d", getMedian(ar1, ar2, n1));      
    else         
        printf("Doesn't work for arrays of unequal size");    
  
    return 0;  
}

方法二:比较两个数组的中位数

ar1[]和ar2[]为输入的数组

算法过程:

1.得到数组ar1和ar2的中位数m1和m2

2.如果m1==m2,则完成,返回m1或者m2

3.如果m1>m2,则中位数在下面两个子数组中

a) From first element of ar1 to m1 (ar1[0...|_n/2_|])
b) From m2 to last element of ar2 (ar2[|_n/2_|...n-1])

4.如果m1<m2,则中位数在下面两个子数组中

a) From m1 to last element of ar1 (ar1[|_n/2_|...n-1])
b) From first element of ar2 to m2 (ar2[0...|_n/2_|])

5.重复上面的过程,直到两个子数组的大小都变成2

6.如果两个子数组的大小都变成2,使用下面的式子得到中位数:Median = (max(ar1[0], ar2[0]) + min(ar1[1], ar2[1]))/2

时间复杂度:O(logn)。

#include <stdio.h>      
  
/* Utility functions */  
int max(int x, int y)   
{       
    return x > y? x : y;  
}    
  
int min(int x, int y)  
{     
    return x > y? y : x;   
}  
  
/* Function to get median of a sorted array */  
int median(int arr[], int n)   
{     
    if (n%2 == 0)         
        return (arr[n/2] + arr[n/2-1])/2;      
    else        
        return arr[n/2];   
}    
  
/*  
This function returns median of ar1[] and ar2[].     
Assumptions in this function:   
Both ar1[] and ar2[] are sorted arrays    
Both have n elements 
*/  
int getMedian(int ar1[], int ar2[], int n)   
{   
    int m1; /* For median of ar1 */    
    int m2; /* For median of ar2 */      
  
    /* return -1  for invalid input */   
    if (n <= 0)         
        return -1;      
    if (n == 1)        
        return (ar1[0] + ar2[0])/2;      
    if (n == 2)        
        return (max(ar1[0], ar2[0]) + min(ar1[1], ar2[1])) / 2;    
  
    m1 = median(ar1, n); /* get the median of the first array */    
    m2 = median(ar2, n); /* get the median of the second array */  
        
    /* If medians are equal then return either m1 or m2 */      
    if (m1 == m2)         
        return m1;         
  
    /* if m1 < m2 then median must exist in ar1[m1....] and ar2[....m2] */    
    if (m1 < m2)    
    {         
        if (n % 2 == 0)            
            return getMedian(ar1 + n/2 - 1, ar2, n - n/2 +1);        
        else        
            return getMedian(ar1 + n/2, ar2, n - n/2);     
    }        
  
    /* if m1 > m2 then median must exist in ar1[....m1] and ar2[m2...] */      
    else     
    {      
        if (n % 2 == 0)          
            return getMedian(ar2 + n/2 - 1, ar1, n - n/2 + 1);          
        else            
            return getMedian(ar2 + n/2, ar1, n - n/2);      
    }   
}   
  
/* Driver program to test above function */  
int main()   
{      
    int ar1[] = {1, 2, 3, 6};    
    int ar2[] = {4, 6, 8, 10};    
    int n1 = sizeof(ar1)/sizeof(ar1[0]);    
    int n2 = sizeof(ar2)/sizeof(ar2[0]);      
    if (n1 == n2)      
        printf("Median is %d", getMedian(ar1, ar2, n1));     
    else      
        printf("Doesn't work for arrays of unequal size");     
  
    return 0;   
}

方法三:通过二分查找法来找中位数

基本思想是:假设ar1[i]是合并后的中位数,那么ar1[i]大于ar1[]中前i-1个数,且大于ar2[]中前j=n-i-1个数。通过ar1[i]和ar2[j]、ar2[j+1]两个数的比较,在ar1[i]的左边或者ar1[i]右边继续进行二分查找。对于两个数组 ar1[] 和ar2[], 先在 ar1[] 中做二分查找。如果在ar1[]中没找到中位数, 继续在ar2[]中查找。

算法流程:
1) 得到数组ar1[]最中间的数,假设下标为i.
2) 计算对应在数组ar2[]的下标j,j = n-i-1 
3) 如果 ar1[i] >= ar2[j] and ar1[i] <= ar2[j+1],那么 ar1[i] 和 ar2[j] 就是两个中间元素,返回ar2[j] 和 ar1[i] 的平均值
4) 如果 ar1[i] 大于 ar2[j] 和 ar2[j+1] 那么在ar1[i]的左部分做二分查找(i.e., arr[left ... i-1])
5) 如果 ar1[i] 小于 ar2[j] 和 ar2[j+1] 那么在ar1[i]的右部分做二分查找(i.e., arr[i+1....right])
6) 如果到达数组ar1[]的边界(left or right),则在数组ar2[]中做二分查找

时间复杂度:O(logn)。

#include <stdio.h>      
  
/* A recursive function to get the median of ar1[] and ar2[] using binary search */  
int getMedianRec(int ar1[], int ar2[], int left, int right, int n)   
{      
    int i, j;   
  
    /* We have reached at the end (left or right) of ar1[] */    
    if(left > right)        
        return getMedianRec(ar2, ar1, 0, n-1, n);    
  
    i = (left + right)/2;      
    j = n - i - 1;  /* Index of ar2[] */      
  
    /* Recursion terminates here.*/     
    if (ar1[i] > ar2[j] && (j == n-1 || ar1[i] <= ar2[j+1]))     
    {        
        /*ar1[i] is decided as median 2, now select the median 1         
        (element just before ar1[i] in merged array) to get the average of both*/     
        if (ar2[j] > ar1[i-1] || i == 0)          
            return (ar1[i] + ar2[j])/2;        
        else            
            return (ar1[i] + ar1[i-1])/2;    
    }  
  
    /*Search in left half of ar1[]*/     
    else if (ar1[i] > ar2[j] && j != n-1 && ar1[i] > ar2[j+1])       
        return getMedianRec(ar1, ar2, left, i-1, n);     
  
    /*Search in right half of ar1[]*/      
    else /* ar1[i] is smaller than both ar2[j] and ar2[j+1]*/    
        return getMedianRec(ar1, ar2, i+1, right, n);   
}  
  
/*  
This function returns median of ar1[] and ar2[].     
Assumptions in this function:    
Both ar1[] and ar2[] are sorted arrays   
Both have n elements  
*/  
int getMedian(int ar1[], int ar2[], int n)   
{     
    // If all elements of array 1 are smaller then     
    // median is average of last element of ar1 and first element of ar2      
    if (ar1[n-1] < ar2[0])      
        return (ar1[n-1]+ar2[0])/2;       
  
    // If all elements of array 1 are smaller then       
    // median is average of first element of ar1 and       
    // last element of ar2      
    if (ar2[n-1] < ar1[0])      
        return (ar2[n-1]+ar1[0])/2;    
    
    return getMedianRec(ar1, ar2, 0, n-1, n);   
}  
  
/* Driver program to test above function */  
int main()   
{     
    int ar1[] = {1, 12, 15, 26, 38};   
    int ar2[] = {2, 13, 17, 30, 45};    
    int n1 = sizeof(ar1)/sizeof(ar1[0]);     
    int n2 = sizeof(ar2)/sizeof(ar2[0]);     
    if (n1 == n2)        
        printf("Median is %d", getMedian(ar1, ar2, n1));      
    else       
        printf("Doesn't work for arrays of unequal size");    
  
    return 0;   
}
0
0
查看评论
发表评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

求两个等长有序数组中位数算法问题

问题:设X[0:n-1]和Y[0:n-1]为两个数组,每个数组中含有n个已排好序的数。试设计一个O(logn)时间算法,找出X和Y的2n个数的中位数 思路:找出将大问题分割成较小规模的相同问题的切割点,并递归定义大问题与子问题之间的关系。 简单来说,就是比较两个区间的中位数,如果第一个区间的中位数比...
  • qq_30189255
  • qq_30189255
  • 2016-03-19 19:52
  • 1026

【分步详解】两个有序数组中的中位数和Top K问题

这也是一道leetcode的经典题目:《LeetCode》解题笔记:004. Median of Two Sorted Arrays[H] 问题介绍 预备知识 先解释下割 割和第k个元素 双数组 如何从双数组里取出第k个元素 假设k3 双数组的奇偶 让数组恒为奇数 映射关系 在虚拟数组里表示割 分治...
  • hk2291976
  • hk2291976
  • 2016-04-09 21:50
  • 4358

给定两个有序数组,找出合并之后的数组中位数

中位数定义:假如一个数组的长度Len为偶数,那么中位数为第 Len/2 个数;如果Len为奇数,那么中位数为第Len/2+1个数。 比如 Arr[ 1, 2, 3, 4, 5]中位数为3;Arr[ 2, 3, 4, 5]中位数为3。 给定两个递增排序数组,请设计一种高效算法求出两个数组的中位数。...
  • HuberJobs
  • HuberJobs
  • 2016-04-09 03:01
  • 3239

寻找两个不等长数组的中位数 Median of Two Sorted Arrays

题目源自于Leetcode。经典好题。 题目: 给出两个有序数组,长度不一定相同,一个是m一个是n,要求给出他们合并在一起之后的数组的中位数。 要求时间复杂度为O(log(m+n)),所以不可以合并数组再找中位数,否则复杂度就是O(m+n)。 数组的中位数 如果有序数组有奇数个元素,那么中位数是...
  • luckyjoy521
  • luckyjoy521
  • 2013-11-10 14:42
  • 3197

在两个有序数组中找到中位数

题目:设X[0:n-1]和Y[0:n-1]为两个数组,每个数组中含有n个已排好序的数,试设计一个O(logn)时间的算法,找出X和Y的2n个数的中位数,并证明算法的时间复杂性为O(logn)。 思路:这题目是在学习完分治算法后留的课后作业,所以,首先想到的就是运用分治的思想。鉴于这两个数组都是有...
  • haiming_yeyeye
  • haiming_yeyeye
  • 2015-10-14 21:41
  • 1092

算法基础 - 查找两个有序数组的中位数

问题描述问题很简单,就是在两个有序的整数数组里(数组A长度为m, 数组B长度为n),找到两个数组合并后的中位数。中位数中位数就是在一个有序数组中,位于中间的数字,假如数组元素个数为偶数,则取两个中间数字的平均数。 例: 1,2,3,4,5 中位数为:3 1,2,3,4 的中位数为:...
  • chenfs1992
  • chenfs1992
  • 2015-11-13 02:07
  • 1385

python找到两个有序列表的中位数

今天做到的一个机试题目,很简单,这里简单记录一下: 我用的是归并的思想,当然还可以用递归的方法,下面是具体实现: #!usr/bin/env python #encoding:utf-8 ''' __Author__:沂水寒城 功能:找到两个有序列表的中位数 若...
  • Together_CZ
  • Together_CZ
  • 2017-08-04 19:44
  • 901

【Leetcode】两个有序数组的中位数

两个有序数组的中位数二分查找法详细理解
  • lxhpkm01
  • lxhpkm01
  • 2016-12-23 00:18
  • 1067

【LeetCode-面试算法经典-Java实现】【004-Median of Two Sorted Arrays(两个排序数组的中位数)】

【004-Median of Two Sorted Arrays(两个排序数组的中位数)】两个排序数组,找这两个排序数组的中位数,时间复杂度为O(log(m+n))采用类二分查找算法
  • DERRANTCM
  • DERRANTCM
  • 2015-07-17 06:39
  • 2960

求两个等长有序数组的中位数的logN算法 分治法

http://blog.csdn.net/yangliuy/article/details/7194199 题目:有两个长为n的非递减数组A和B,把B接在A的后面变成长为2n的数组C。设计算法求C的中位数(第n小数)。 思路:O(n)的算法很容易找到,关键是用二分的思想设计l...
  • haluoluo211
  • haluoluo211
  • 2014-12-17 19:32
  • 1046
    个人资料
    • 访问:92328次
    • 积分:3242
    • 等级:
    • 排名:第12200名
    • 原创:226篇
    • 转载:40篇
    • 译文:2篇
    • 评论:7条
    最新评论