1 <?php 2 #最大递增子序列的查找 3 function max_subincseq($a) { 4 $len = count($a); 5 $lis = array(); #lis数组用于存储当前最长子序列长度,lis[i]表示以a[i]结尾的最长递增子序列长度 6 $lis[0] = 1; 7 $max_seqlen = 1; 8 9 for ($i = 1; $i < $len; $i++) { 10 $lis[$i] = 1; 11 for ($j = 0; $j < $i; $j++) { 12 if ($a[$i] > $a[$j] && $lis[$j] + 1 > $lis[$i]) { 13 $lis[$i] = $lis[$j] + 1; 14 } 15 } 16 17 if ($lis[$i] > $max_seqlen) $max_seqlen = $lis[$i]; 18 } 19 20 return $max_seqlen; 21 } 22 23 #多用一个辅助数组max_v,max_v[i] = a[k] 表示最大子序列长度为i的最后一个元素的最小值是a[k] 24 #时间复杂度O(nlogn),空间复杂度O(n) 25 function max_subincseq2($a) { 26 $len = count($a); 27 $lis = array(); 28 $lis[0] = 1; 29 $max_v = array(); 30 $max_v[0] = min($a) - 1; 31 $max_v[1] = $a[0]; 32 $max_seqlen = 1; 33 34 for ($i = 1; $i < $len; $i++) { 35 $lis[$i] = 1; 36 // for ($clen = $max_seqlen; $clen >= 1; $clen--) { #从前一个子序列往前找到一个符合条件的最长的子序列长度 37 // if ($a[$i] > $max_v[$clen]) { 38 // $lis[$i] = $clen + 1; 39 // break; 40 // } 41 // } 42 #max_v是一个单调递增数列,查找a[i] < max_v[clen]可以使用二分 43 $h = 1; 44 $t = $max_seqlen; 45 $mid = floor(($h + $t) / 2); 46 while ($h <= $t) { 47 if ($max_v[$mid] >= $a[$i]) { 48 $t = $mid - 1; 49 } else { 50 if ($mid + 1 > $max_seqlen || $max_v[$mid + 1] >= $a[$i]) { 51 $clen = $mid; 52 break; 53 } else { 54 $h = $mid + 1; 55 } 56 } 57 $mid = floor(($h + $t) / 2); 58 } 59 60 if (isset($clen)) { 61 $lis[$i] = $clen + 1; 62 } 63 64 #维护max_v和max_seqlen 65 if (!isset($max_v[$lis[$i]])) { 66 #如果当前最大序列长度比总最大长度还大 67 #更新信息 68 $max_v[$lis[$i]] = $a[$i]; 69 $max_seqlen = $lis[$i]; 70 } else if ($a[$i] < $max_v[$lis[$i]]) { 71 #否则如果当前元素小于当前最大子序列最后一个元素的最小值,更新max_v 72 $max_v[$lis[$i]] = $a[$i]; 73 } 74 } 75 76 return $max_seqlen; 77 } 78 79 $a = array(5, 6, 2, 7, 4, 0, -1, 2, 9); 80 echo max_subincseq($a) . "<br>"; 81 echo max_subincseq2($a); 82 ?>