算法思路:每次取两个数组的中位数进行比较,如图
我们假定取的中位数是下中位数,即每次取中位数坐标时使用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 )