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_seqlen65 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_v72 $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 ?>