求解數組的最大子數組
/*
求解數組的最大子數組最大子數組定義:
數組的和最大的非空連續子數組
測試數組:$arr = array(13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7);
最大子數組 $arr1 = array(18,20,-7,12); //和爲43
*/
方法一:暴力求解法
/*
方法一:暴力求解法
沒什麼新鮮的,兩層for循環窮舉法*/
function maxSonArr($arr){
$max=$arr[0];
$num = count($arr);
for($m=0;$m<$num;$m++){
$sum = $arr[$m];
for($n=$m+1;$n<$num;$n++){
$sum += $arr[$n];
if($sum>$max){
$max = $sum;
$left = $m;
$right = $n;
}
}
}
$sonArr = array($max,$left,$right);
return $sonArr;
} // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
$arr = array(13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7);
print_r( maxSonArr($arr));
方法二:分治求解法
將數組劃分爲兩個儘量相等的子數組,下標直接取中間值即可。此時,該子數組所處的位置有以下三種可能
一、完全位於0-mid子數組中
二、完全位於mid-count(arr)子數組中
三、跨越中間點 low<mid<high
其中,這個方法代碼太冗餘了,可以通過使用遞歸簡化代碼
可以將左邊最大值、右邊最大值看作包含中間元素的左邊、右邊最大值的遞歸
eg:數組20個元素,假設左邊最大值爲元素序號3-6 可以遞歸到邊界爲5,此時就是包含中間元素了 ,代碼就不寫了
function maxSubArr($arr){ $num = count($arr); $mid = floor($num/2); $leftMaxSum = $arr[$mid]; $rightMaxSum = $arr[$mid+1]; //左邊最大值 for($m=$mid-1;$m>=0;$m--){ $lsftSum = $arr[$m]; for($n=$m-1;$n>=0;$n--){ $lsftSum += $arr[$n]; if($leftMaxSum<$leftSum){ $leftMaxSum = $leftSum; } } } //右邊最大值 for($m=$mid;$m<$num;$m++){ $rightSum = $arr[$m]; for($n=$m+1;$n<$num;$n++){ $rightSum += $arr[$n]; if($rightMaxSum<$rightSum){ $rightMaxSum = $rightSum; } } } //包含中間的左邊最大值 for($m=$mid-1;$m>=0;$m--){ $leftMidSum += $arr[$m]; if($leftMidMaxSum<$leftMidSum){ $leftMidMaxSum = $leftMidSum; } } //包含中間的右邊最大值 for($m=$mid;$m<=$num;$m++){ $rightMidSum += $arr[$m]; if($rightMidMaxSum<$rightMidSum){ $rightMidMaxSum = $rightMidSum; } } $midMaxSum = $leftMidMaxSum+$rightMidMaxSum; $MaxSubSum = $rightMaxSum; if($leftMaxSum>$MaxSubSum){ $MaxSubSum = $leftMaxSum; } if($midMaxSum>$MaxSubSum){ $MaxSubSum = $leftMidMaxSum + $rightMidMaxSum; } return $MaxSubSum; } //var_dump(maxSubArr($arr));