PHP 两个等长有序数组求合并后的中位数

算法思路:每次取两个数组的中位数进行比较,如图

我们假定取的中位数是下中位数,即每次取中位数坐标时使用floor取出,当数组长度是奇数时,取得是正中间的元素,是偶数时取得就是下中位数

1. a[n/2] == b[n/2],可知中位数即为a[n/2],返回即可

2. a[n/2] < b[n/2],设a,b数组蓝色红色部分元素分别为a[b],a[r],b[b],b[r],

可知 a[b] <= a[n/2] < b[n/2] <= b[b]

于是有 a[b] <= a[r], a[b] < b[b] (数组元素可能存在重复)

b[b] >= b[r] , b[b] > a[b]

这样我们就知道了a[b]中的元素至少小于n个元素,b[b]中的元素至少大于n个元素,易知中位数就不可能在蓝色部分了

那么排除了蓝色部分以后,就可以对红色部分重新用取中位数的方法来查找总的中位数,直到切分后的数组只剩一个元素,我们取较小的那个元素即可

那么在从中位数坐标切分数组时,我们到底要不要把中位数元素也放入红色部分呢?这里有两种情况

1)当n为奇数时,我们需要把a,b的中位数都放入红色部分进行递归查找,因为当a,b数组合并后,a[n/2] b[n/2]仍然有可能排在合并数组的正中间,那么中位数就是二者其一

举个例子, a = (1,3,5,7,9), b = (2,4,6,8,10),最后拍出来肯定是1,2,3,4,5,6,7,8,9,10,可见这里5,6都是中位数

2)当n为偶数时,我们需要将较小的那个中位数排除掉,只让他右边的红色部分进入递归查找(这里是排除a[n/2],如果a[n/2] > b[n/2],则排除b[n/2])

这是因为如果数组长度是偶数,那么我们取的中位数肯定是下中位数,且a[n/2] < b[n/2],则数组合并以后a[n/2]肯定位于总中位数的左边,所以a[n/2]肯定不是最后的中位数

举个例子, a = (1,3,5,7), b = (2,4,6,8),则最后排出来是12345678,我们取的中位数是3, 4,可见3不可能是中位数,中位数是4,5

好了。下面看代码

 1 <?php
 2     #两个长度皆为n的数组,两个数组已排序,求两个数组所有数字中的中位数
 3     function get_mid($a, $b) {
 4         print_r($a);
 5         echo "<br>";
 6         print_r($b);
 7         echo "<br>";
 8         if (count($a) == 1) {
 9             $result_mid = min($a[0], $b[0]); #如果数组只剩一个元素,返回这个元素即为中位数
10         } else {
11             $mid = floor((count($a) - 1) / 2); #中位数坐标取下中位数
12             echo "mid : {$mid}<br>";
13 
14             #如果a[mid] == b[mid],则中位数就是mida,返回即可
15             #如果a[mid] < b[mid],选择数组a的右部,数组b的左部进入递归,直到最后递归部分数组长度为1
16             #如果a[mid] > b[mid],选择数组a的左部,数组b的右部进入递归,直到最后递归部分数组长度为1
17 
18             #此处需要特别注意,当数组长度为奇数时,切分AB数组都要把中位数加上
19             #但数组长度为偶数时,只需要把较大的数组的左部加上中位数,较小的数组则舍弃中位数只要右部进入递归
20 
21             if (count($a) % 2 == 0) {
22                 $small_arr_start = $mid + 1;
23             } else {
24                 $small_arr_start = $mid;
25             }
26 
27             if ($a[$mid] == $b[$mid]) { #两数组中位数相等,返回中位数
28                 $result_mid = $a[$mid];
29             } else if ($a[$mid] < $b[$mid]) { #此处需要特别注意
30                 $atemp = array_slice($a, $small_arr_start); #切分数组,较小的数组根据长度是否是奇偶舍弃中位数
31                 $btemp = array_slice($b, 0, $mid + 1);
32                 $result_mid = get_mid($atemp, $btemp);
33             } else {
34                 $atemp = array_slice($a, 0, $mid + 1);
35                 $btemp = array_slice($b, $small_arr_start);
36                 $result_mid = get_mid($atemp, $btemp);
37             }
38         }
39 
40         return $result_mid;
41     }
42 
43     $a = array(1, 3, 5, 5, 7, 8, 9);
44     $b = array(2, 2, 7, 8, 9, 10, 14);
45 
46     echo "midnum : " . get_mid($a, $b) . "<br>";
47 
48     array_splice($a, count($a) - 1, 0, $b);
49     sort($a);
50 
51     print_r($a);
52 ?>

 Array ( [0] => 1 [1] => 3 [2] => 5 [3] => 5 [4] => 7 [5] => 8 [6] => 9 ) 
Array ( [0] => 2 [1] => 2 [2] => 7 [3] => 8 [4] => 9 [5] => 10 [6] => 14 ) 
mid : 3
Array ( [0] => 5 [1] => 7 [2] => 8 [3] => 9 ) 
Array ( [0] => 2 [1] => 2 [2] => 7 [3] => 8 ) 
mid : 1
Array ( [0] => 5 [1] => 7 ) 
Array ( [0] => 7 [1] => 8 ) 
mid : 0
Array ( [0] => 7 ) 
Array ( [0] => 7 ) 
midnum : 7
Array ( [0] => 1 [1] => 2 [2] => 2 [3] => 3 [4] => 5 [5] => 5 [6] => 7 [7] => 7 [8] => 8 [9] => 8 [10] => 9 [11] => 9 [12] => 10 [13] => 14 )

原文地址:https://www.cnblogs.com/zemliu/p/2703287.html