找两个有序数组的中位数的几种方式

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了找两个有序数组的中位数的几种方式相关的知识,希望对你有一定的参考价值。

我用5个思路的来解决两个非减序数组的中位数.但是成功的只有四个,思路3边界问题太严重.
有时间再来弄好他,他在考试中也不适合使用(边界问题没法快速解决,网上也有人说小数据枚举法确定边界),总的来说费事.

主函数:

#include <stdio.h>
#include <time.h>
#include <limits.h>

double findMedianSortedArrays_1(int* nums1, int nums1Size, int* nums2, int nums2Size);
double sss(int a[], int m, int b[], int n, int k);
double findMedianSortedArrays_2(int* nums1, int nums1Size, int* nums2, int nums2Size);
double findMedianSortedArrays_3(int* nums1, int nums1Size, int* nums2, int nums2Size);
double findMedianSortedArrays_4(int* nums1, int nums1Size, int* nums2, int nums2Size);
double findMedianSortedArrays_5(int* nums1, int nums1Size, int* nums2, int nums2Size);

int main() 
clock_t start_t, end_t;
double total_t;
double mid = 0;
//    1  2  3  4  5  6  7   8   9   10   11
int str1[1000] =  0, 2, 4, 5, 7, 9, 10, 15, 21, 23, 25 , \\
    str2[1000] =  5, 6, 9, 15, 17, 18, 20, 23, 24, 26, 27, 29, 50 ;
//    1  2  3  4    5   6   7   8  9   10  11   12  13
start_t = clock();
mid = findMedianSortedArrays_1(str1, 11, str2, 13);
end_t = clock();
total_t = (double)((double)end_t - (double)start_t) / CLOCKS_PER_SEC;
printf("方法1:CPU 占用的总时间:%f ns\\n", (total_t * 1000000000));
printf("中位数 %f \\r\\n", mid);

start_t = clock();
mid = findMedianSortedArrays_2(str1, 11, str2, 13);
end_t = clock();
total_t = (double)((double)end_t - (double)start_t) / CLOCKS_PER_SEC;
printf("方法2:CPU 占用的总时间:%f ns\\n", (total_t * 1000000000));
printf("中位数 %f \\r\\n", mid);

start_t = clock();
mid = findMedianSortedArrays_3(str1, 11, str2, 13);
end_t = clock();
total_t = (double)((double)end_t - (double)start_t) / CLOCKS_PER_SEC;
printf("方法3:CPU 占用的总时间:%f ns\\n", (total_t * 1000000000));
printf("中位数 %f \\r\\n", mid);

start_t = clock();
mid = findMedianSortedArrays_4(str1, 11, str2, 13);
end_t = clock();
total_t = (double)((double)end_t - (double)start_t) / CLOCKS_PER_SEC;
printf("方法4:CPU 占用的总时间:%f ns\\n", (total_t * 1000000000));
printf("中位数 %f \\r\\n", mid);

start_t = clock();
mid = findMedianSortedArrays_5(str1, 11, str2, 13);
end_t = clock();
total_t = (double)((double)end_t - (double)start_t) / CLOCKS_PER_SEC;
printf("方法5:CPU 占用的总时间:%f ns\\n", (total_t * 1000000000));
printf("中位数 %f \\r\\n", mid);

return 0;

思路一:

/*
方法1:采用归并两个非减数组形成新非减数组,然后求取新数组的中位数.
性能分析:归并两数组的时间复杂度O(n+m),查找中位数时间复杂度O(1).所以时间复杂度O((n+m)*1)=O(m+n)
*/
double findMedianSortedArrays_1(int* nums1, int nums1Size, int* nums2, int nums2Size) 
int i = 0, j = 0, k = 0;
int c[10000] =  0 ;
double mid_f = (nums1Size + nums2Size);
int sign = (!((int)mid_f & 0x1));
if ((!nums1Size) && (!nums2Size))return -1;
/* mid_f = (mid_f / 2);
if (nums1Size == 0) 
return ((nums2[(int)mid_f] + nums2[(int)(mid_f - sign)]) / 2);

if (nums2Size == 0) 
return ((nums1[(int)mid_f] + nums1[(int)(mid_f - sign)]) / 2);
 */
while ((i < nums1Size) && (j < nums2Size))

c[k++] = (nums1[i] <= nums2[j]) ? nums1[i++] : nums2[j++];

while (i < nums1Size)

c[k++] = nums1[i++];

while (j < nums2Size)

c[k++] = nums2[j++];

// mid_f = (k & 0x1)? (c[(k / 2)]):(((c[(k / 2 + sign)]) + (c[(k / 2)])) / 2);
mid_f = (((c[(k / 2 - sign)]) + (c[(k / 2)])) / 2);

printf("OK k = %d  (nums1Size + nums2Size) = %d  i = %d j  = %d  \\r\\n", k, (nums1Size + nums2Size), i, j);
i = 0;
while(i <= k)

printf("c[%d] = %d \\r\\n", i, c[i]);
i++;


return mid_f;

思路二:

double findMedianSortedArrays_2(int* nums1, int nums1Size, int* nums2, int nums2Size) 
int length_c = (nums1Size + nums2Size);
if (length_c == 0)return 0;
if (length_c & 0x1)

return sss(nums1, nums1Size, nums2, nums2Size, ((length_c / 2) + 1));

else

return (((sss(nums1, nums1Size, nums2, nums2Size, (length_c / 2))) + (sss(nums1, nums1Size, nums2, nums2Size, ((length_c / 2) + 1)))) / 2);



double sss(int a[], int m, int b[], int n, int k)

//always assume that m is equal or smaller than n
if (m > n)
return sss(b, n, a, m, k);
if (m == 0)
return b[k - 1];
if (k == 1)
// return min(a[0], b[0]);
return (a[0] < b[0]) ? a[0] : b[0];
//divide k into two parts
// int pa = min(k / 2, m), pb = k - pa;
int pa = ((k / 2) < m) ? (k / 2) : m, pb = k - pa;
if (a[pa - 1] < b[pb - 1])
return sss(a + pa, m - pa, b, n, k - pa);
else if (a[pa - 1] > b[pb - 1])
return sss(a, m, b + pb, n - pb, k - pb);
else
return a[pa - 1];

方法三:

 double findMedianSortedArrays_3(int* nums1, int nums1Size, int* nums2, int nums2Size) 
int mid1 = (nums1Size / 2), mid2 = (nums2Size / 2); /* even number slect little one,other slect midle one. */
mid1 = (nums1Size == 2) ? (0) : (mid1);
/*nums1Size或nums2Size等于2时,mid 的取值为1,违反了数组长为偶数时,选择中位数下标较小的那个一作为中位数,这一原则.*/
mid2 = (nums2Size == 2) ? (0) : (mid2);
if ((nums1Size == 1) && (nums2Size == 1))

return ((nums1[0] + nums2[0]) / 2);

else if (nums1Size == 1)

if (((nums2Size % 2) == 0))

if (nums1[0] <= nums2[mid2])

return (nums2[mid2]);

else

if (nums1[0] > nums2[mid2 + 1])

return (nums2[(mid2 + 1)]);

else

return (nums1[0]);



//这里要考虑nums2[(mid2 - k)]和nums2[(mid2 + k)] (k=1,2,...length(nums2)/2)同nums2[mid2]是否相等的情况!!这样才能保证边界清晰.
else

if (nums1[0] <= nums2[(mid2 - 1)])

return ((nums2[(mid2 - 1)] + (nums2[mid2])) / 2);

else if (nums1[0] >= nums2[(mid2 + 1)])

return ((nums2[mid2]) + (nums2[(mid2 + 1)]) / 2);

else /*nums2[(mid2 - k)]<nums2[0]、nums1[mid2]<nums2[(mid2 + k)]*/

return ((nums2[mid2] + nums1[0]) / 2);



else if (nums2Size == 1)
/*这里有问题,边界不对.*/
printf("###   nums1Size = %d   nums1[%d] = %d     nums2Size = %d  nums2[%d] = %d \\r\\n", nums1Size, mid1, nums1[mid1], nums2Size, mid2, nums2[mid2]);
if (((nums1Size % 2) == 0))

if (nums2[0] <= nums1[mid1])

return (nums1[mid1]);

else

if (nums2[0] > nums1[mid1 + 1])

return (nums1[(mid1 + 1)]);

else

return (nums2[0]);



//这里要考虑nums1[(mid1 - k)]和nums1[(mid1 + k)] (k=1,2,...length(nums1)/2)同nums1[mid1]是否相等的情况!!这样才能保证边界清晰.
else

if (nums2[0] <= nums1[(mid1 - 1)])

return ((nums1[(mid1 - 1)] + (nums1[mid1])) / 2);

else if (nums2[0] >= nums1[(mid1 + 1)])

return ((nums1[mid1]) + (nums1[(mid1 + 1)]) / 2);

else /*nums1[(mid1 - k)]<nums2[0]、nums1[mid1]<nums1[(mid1 + k)]*/

return ((nums1[mid1] + nums2[0]) / 2);



if (nums1[mid1] == nums2[mid2])

return nums1[mid1];

else if (nums1[mid1] < nums2[mid2]) /* [mid1...n] & [0...mid2] */

return findMedianSortedArrays_3(&nums1[mid1], (nums1Size - mid1), &nums2[0], (mid2 + 1));

else /* [0...mid1] & [mid2...m] */

return findMedianSortedArrays_3(&nums1[0], (mid1 + 1), &nums2[mid2], (nums2Size - mid2));

return 0;

方法四:

/* 
从某种程度上来说这是每数组的中位数对比法的一种更完善的思想.通过对比每数组的割处,a[li]<b[(a.length+b.length+1-li)+1]和b[a.length+b.length+1-li]<a[li+1]同时成立作为退出条件,其他区间为循环和二分法依据.采用manacher算法的技巧实现奇偶性的统一化处理.
性能分析:通过上述的循环查找缩小a数组一半的元素个数,但是最坏要经过m+n次循环.时间复杂度O(log(n+m))
 */
/////////////////////////////////*************4********************//////////////////////////////////
double findMedianSortedArrays_4(int* nums1, int nums1Size, int* nums2, int nums2Size) 
int length_c = (nums1Size + nums2Size);
int len_a = nums1Size, len_b = nums2Size;
int la = 0, lb = 0, ra = 0, rb = 0;
int ca = 0, cb = 0;
int low = 0, high = (2 * len_a);

if ((nums1Size == 0) && (nums2Size == 0))return -1;
if (nums1Size == 0) 
return ((nums2[nums2Size / 2] + nums2[nums2Size / 2 - 1]) / 2);

if (nums2Size == 0) 
return ((nums1[nums1Size / 2] + nums1[nums1Size / 2 - 1]) / 2);

if (nums1Size > nums2Size)

return findMedianSortedArrays_4(nums2, nums2Size, nums1, nums1Size);

while (low <= high)

ca = ((low + high) / 2);
cb = len_a + len_b - ca;
la = (ca == 0) ? (INT_MIN) : (nums1[((ca - 1) / 2)]);
ra = (ca == (2 * len_a)) ? (INT_MAX) : (nums1[(ca / 2)]);
lb = (cb == 0) ? (INT_MIN) : (nums2[((cb - 1) / 2)]);
rb = (cb == (2 * len_b)) ? (INT_MAX) : (nums2[(cb / 2)]);
printf("la = %d ra = %d lb = %d rb = %d \\r\\n", la, ra, lb, rb);
if (la > rb) 
high = ca - 1;/*二分法的上限移动到中点少1的位置处,抛弃后半部分一半多1个元素.*/

else if (lb > ra) 
low = ca + 1;/*二分法的下限移动到中点多1的位置处,抛弃前半部分一半多1个元素.*/

else /*else if(la <= rb && lb <= ra)*/
break;


return ((((la >= lb) ? (la) : (lb)) + ((ra <= rb) ? (ra) : (rb))) / 2);

LeetCode-;两有序数组找中位数答案

方法五:

/* 
用统计方法,从小到大对两数组同时进行归并式的遍历,并计数.当计数值等于两数组的中位数的下标,就找到中位数.
性能分析:时间复杂度是归并时间复杂度的一半,即O(m+n)=O((m+n)/2)
 */
double findMedianSortedArrays_5(int* nums1, int nums1Size, int* nums2, int nums2Size) 
int i = 0, j = 0, k = 0;
int middle = (nums1Size + nums2Size);
double sign = (!(middle & 0x1));
if ((nums1Size == 0) && (nums2Size == 0))return -1;
middle = (middle / 2);
if (nums1Size == 0) 
return ((nums2[(int)middle] + nums2[(int)(middle - sign)]) / 2);

if (nums2Size == 0) 
return ((nums1[(int)middle] + nums1[(int)(middle - sign)]) / 2);

if (sign) 
for (i = 0, j = 0, k = 0; i <= (int)(middle - sign); i++)

(nums1[j] <= nums2[k]) ? (nums1[(j++)]) : (nums2[k++]);

middle = (nums1[j] <= nums2[k]) ? (nums1[j--]) : (nums2[k--]);//偶数中位数的前半部分最大值
middle = ((middle + ((nums1[j] <= nums2[k]) ? (nums1[j]) : (nums2[k]))) / 2);//[偶数中位数的后半部分最小值 + middle(偶数中位数的前半部分最大值)] / 2 = middle

else

for (i = 0, j = 0, k = 0; i <= (middle - sign); i++)

(nums1[j] <= nums2[k]) ? (nums1[(j++)]) : (nums2[k++]);

middle = (nums1[j] <= nums2[k]) ? (nums1[j]) : (nums2[k]);

return middle;

测试结果:(出现的特例:这着实具有不可避免性.输入全体样本中重复率高时,结束条件能被错误触发.)

/*

OK k = 24  (nums1Size + nums2Size) = 24  i = 11 j  = 13

c[0] = 0

c[1] = 2

c[2] = 4

c[3] = 5

c[4] = 5

c[5] = 6

c[6] = 7

c[7] = 9

c[8] = 9

c[9] = 10

c[10] = 15

c[11] = 15

c[12] = 17

c[13] = 18

c[14] = 20

c[15] = 21

c[16] = 23

c[17] = 23

c[18] = 24

c[19] = 25

c[20] = 26

c[21] = 27

c[22] = 29

c[23] = 50

c[24] = 0

方法1:CPU 占用的总时间:4000000.000000 ns

中位数 16.000000

方法2:CPU 占用的总时间:0.000000 ns

中位数 16.000000

nums1Size = 11   nums1[5] = 9     nums2Size = 13  nums2[6] = 20

nums1Size = 6   nums1[3] = 21     nums2Size = 7  nums2[3] = 15

nums1Size = 4   nums1[2] = 15     nums2Size = 4  nums2[2] = 18

nums1Size = 2   nums1[0] = 15     nums2Size = 3  nums2[1] = 17

nums1Size = 2   nums1[0] = 15     nums2Size = 2  nums2[0] = 15

方法3:CPU 占用的总时间:15000000.000000 ns

中位数 15.000000

la = 9  ra = 9          lb = 20 rb = 20

la = 21 ra = 21         lb = 15 rb = 15

la = 10 ra = 15         lb = 17 rb = 18

la = 15 ra = 15         lb = 17 rb = 17

la = 15 ra = 21         lb = 15 rb = 17

方法4:CPU 占用的总时间:10000000.000000 ns

中位数 16.000000

方法5:CPU 占用的总时间:0.000000 ns

中位数 16.000000

*/

参考技术A package test;

import java.util.Arrays;
import java.util.Comparator;

public class JButtonTest

public static void main ( String[] args )

int[] arr1 = 3, 1, 23 ;
int[] arr2 = 27, 7, 2 ;
String temp = Arrays.toString (arr1) + Arrays.toString (arr2);
temp = temp.replaceAll ("\\]\\[", ",").replaceAll ("\\s", "").replaceAll ("[\\[\\]]", "");
String[] result = temp.split ("\\,");
System.out.println (Arrays.toString (result));
Arrays.sort (result, new Comparator<String> ()

@Override
public int compare ( String o1, String o2 )

int a = Integer.parseInt (o1), b = Integer.parseInt (o2);
if (a > b)

return 1;

else if (a < b)

return -1;

else

return 0;


);
System.out.println (Arrays.toString (result));

Leetcode 寻找两个有序数组的中位数

2020-04-26

原题链接

  • 思路

题意就是寻找两个有序数组的中位数。第一反应可能会先把两个数组合并然后再找中位数,但是显然我们没有必要把合并后的数组存起来,只要依次搜索,得到最中间的一个或两个就可。美中不足的是它的时间复杂度为 O(m + n)

为了达到题目中时间复杂度为 O(log(m + n)) 的要求,我们可以使用二分(其实也是看了题解后 ohhhhhhh )。前面我们是一个一个剔除,现在我们可以一次剔除 (m + n) / 4 个。直接比较 nums1[(m+n)/4]nums2[(m+n)/4] ,若 nums1[(m+n)/4] 小,则它和它之前的部分就可以被直接剔除,因为他们一定是在中位数之前(我也想过是否也可以把 nums2[(m+n)/4] 之前的也去掉呢,答案是不可以)。以这个思路反复直到得到 (m + n) / 2(m + n) / 2 + 1 位的两个数。这个方法的边界判断烦得不行,更有趣的是要注意 [] [1] 类似的各种极端情况。

顺便吐嘈一句这个垃圾网站 coding 体验极差 hhh

  • 代码

O(m + n):

/*
 *lang C++
 *user weilinfox
 */
class Solution {
public:
    static double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        long long a = nums1.size(), b = nums2.size();
        int t, tp;
        for (long long i = 0, j = 0; i + j + 1 <= (a + b) / 2 + 1;) {
            tp = t;
            if (i < a && j < b) {
                t = nums1[i];
                if (t > nums2[j]) {
                    t = nums2[j];
                    j++;
                } else
                    i++;
            } else if (i < a)
                t = nums1[i++];
            else
                t = nums2[j++];
        }
        a += b;

        if (a % 2 == 0)
            return (double)(t + tp) / 2.0;
        else
            return (double)t;
            
    }
};

by SDUST weilinfox
本文链接 https://www.cnblogs.com/weilinfox/p/12781374.html

以上是关于找两个有序数组的中位数的几种方式的主要内容,如果未能解决你的问题,请参考以下文章

Leet Code 4.寻找两个有序数组的中位数

Leetcode 寻找两个有序数组的中位数

每天一道Leecode——寻找两个正序数组的中位数,腾讯高频面试题分享!

算法作业!!求两个不等长有序数组的中位数!

Leetcode寻找两个有序数组的中位数

[LeetCode] 寻找两个有序数组的中位数