[英]How can I improve my PHP code to make it more efficient?
我編寫了一個簡單的PHP腳本,該腳本檢查隨機值是否為有效的橄欖球聯合得分。 它工作得很好,但效率不是特別高,因此歡迎提供任何改進建議。
$score = rand(0, 60);
/* Rugby Union
*
* Try = 5 points
* Conversion = 2 points
* Penalty = 3 points
* Drop goal = 3 points
*
*/
echo "<h1>Score: ".$score."</h1>";
for ($tries = 0; $tries <= 12; $tries++)
{
for ($conversions = 0; $conversions <= 30; $conversions++)
{
for ($dropgoals = 0; $dropgoals <= 20; $dropgoals++)
{
if ($conversions > $tries)
{
//echo "<br />Illegal score";
}
else
{
$testscore = ($tries * 5) + ($conversions * 2) + ($dropgoals * 3);
if ($testscore == $score)
{
if ($dropgoals == 0)
{
echo "Found a way to achieve score with ".$tries." tries ".$conversions." conversions and ".$dropgoals." drop goals.<br />";
}
else
{
echo "Found a way to achieve score with ".$tries." tries ".$conversions." conversions and ".$dropgoals." drop goals or penalties.<br />";
}
}
}
}
}
}
好的,這是目前的修訂解決方案,如果可能的話,減少嵌套的for循環數量會很不錯。
echo "<h1>Score: ".$score."</h1>";
for ($tries = 0; $tries <= 12; $tries++) {
for ($conversions = 0; $conversions <= $tries; $conversions++) {
for ($dropgoals = 0; $dropgoals <= 20; $dropgoals++){
if ($conversions <= $tries) {
$testscore = ($tries * 5) + ($conversions * 2) + ($dropgoals * 3);
if ($testscore == $score) {
echo "Found a way to achieve score with ".$tries." tries ".$conversions." conversions and ".$dropgoals.($dropgoals == 0 ? " drop goals.<br />" : " drop goals or penalties.<br />");
}
}
}
}
}
好吧開始
for ($conversions = 0; $conversions <= 30; $conversions++)
可以更改為
for ($conversions = 0; $conversions <= $tries; $conversions++)
實際上,只有可能的分數是有限的,對吧? 快速的Google顯示記錄為164點。 因此,為什么不一次生成每個可能得分的列表,直到最大分數(300?500?),並在您的應用中對其進行硬編碼。 然后,在運行時,只需檢查提供的分數是否在列表中。 我認為,到目前為止,這將是最有效的解決方案。
編輯:如果您還想輸出嘗試次數,罰分次數和掉球目標-只需一次生成這些值,並將它們也保留在列表中(作為二維數組或關聯數組)。
當您說“有效”時,請定義您的意思。
代碼執行太慢嗎? 現在它運行速度有多快,您需要它運行多快? 如果您不能定義“不夠快”,那么您就沒有目標。
在您猜出要加速什么之前,在這里所有的受訪者都在鼓勵您加快散布速度對您的傷害之前,您需要分析代碼以了解大部分時間在哪里。
您的if else函數應該反轉。 使最可能的情況出現在if(){}子句中,並在else {}中出現異常錯誤
if ($conversions < $tries)
{
$testscore = ($tries * 5) + ($conversions * 2) + ($dropgoals * 3);
if ($testscore == $score)
{
if ($dropgoals == 0)
{
echo "Found a way to achieve score with ".$tries." tries ".$conversions." conversions and ".$dropgoals." drop goals.<br />";
}
else
{
echo "Found a way to achieve score with ".$tries." tries ".$conversions." conversions and ".$dropgoals." drop goals or penalties.<br />";
}
}
}
else
{
// echo "illegal score";
}
這樣可以清理一些東西。
echo "Found a way to achieve score with ".$tries." tries ".$conversions." conversions and ".$dropgoals.($dropgoals == 0 ? " drop goals.<br />" : " drop goals or penalties.<br />");
稍作修改的版本。 我希望我對橄欖球有所了解。
$score = rand(0, 60);
/* Rugby Union
*
* Try = 5 points
* Conversion = 2 points
* Penalty = 3 points
* Drop goal = 3 points
*
*/
echo "<h1>Score: ".$score."</h1>";
for ($tries = 0; $tries <= 12; $tries++){
for ($conversions = 0; $conversions <= $tries; $conversions++){
for ($dropgoals = 0; $dropgoals <= 20; $dropgoals++){
else{
$testscore = ($tries * 5) + ($conversions * 2) + ($dropgoals * 3);
if ($testscore == $score){
if ($dropgoals == 0){
echo "Found a way to achieve score with ".$tries." tries ".$conversions." conversions and ".$dropgoals." drop goals.<br />";
}
else{
echo "Found a way to achieve score with ".$tries." tries ".$conversions." conversions and ".$dropgoals." drop goals or penalties.<br />";
}
}
}
}
}
if ($conversions > $tries){
echo "<br />Illegal score";
}
}
找到解決方案后,您還可以跳出循環:
if ($testscore == $score)
{
echo "Found a way to achieve ....";
break 3;
}
數指明循環的數量打破了,所以在寫作時有3 for
循環退出。
是的,對於這樣的問題,3次循環似乎太多了。 但是,當您想找到x,y,z的組合,使得n = x*5 + y*3 + z*2
且x>=z
,我認為沒有簡單的解決方案。 但是,您可以減少迭代次數。
最好知道是要獲得所有可能的組合還是只是想回答“是的,這是有效分數”。
無論如何,這是我的建議:
$score = rand(0, 60);
/* Rugby Union
*
* Try = 5 points
* Conversion = 2 points
* Penalty = 3 points
* Drop goal = 3 points
*
*/
// compute how often the points fit into the score
$maxTries = intval($score / 5);
$maxConversions = min(intval($score / 2),$maxTries);
$maxDrops = intval($score / 3);
$valid = false;
for ($tries = 0; $tries <= $maxTries; $tries++)
{
// this way, you avoid recomputing the value over and over again in the third loop
$scoreTries = $tries * 5;
for ($conversions = 0; $conversions <= $maxConversions; $conversions++)
{
$scoreCons = $scoreTries + $conversions * 2;
for ($dropgoals = 0; $dropgoals <= $maxDrops; $dropgoals++)
{
$scoreTotal = $scoreCons + $dropgoals * 3
if ($scoreTotal == $score)
{
echo 'Found a way to achieve score with '.$tries.' tries '.$conversions.' conversions and '.$dropgoals.' drop goals or penalties.<br />';
$valid = true;
// write 'break 3' here if you are satisfied with one answer
}
}
}
}
if (!$valid){
echo "<br />Illegal score";
}
我不知道效率會提高多少,但是總的來說,如果使用“點”語法將字符串括在單引號(“字符串”)中總是很好的。 這樣,PHP不會評估字符串以替換變量,我認為這是一種更干凈的方法。
編輯:
哦,我不區分$dropgoals == 0
,因為從邏輯上說,例如...and 0 drop goals.
之間沒有區別...and 0 drop goals.
和...and 0 drop goals or penalties.
這與找出如何用給定面額的硬幣組成零錢是一個同樣的問題。 這是PHP的實現。 我懷疑它是否非常有效,但是比嵌套循環版本更通用。
<?php
f(
30, // points scored in match
array( // rugby union scoring structure
"Converted Tries" => 7,
"Unconverted Tries" => 5,
"Drop Goals/Penalties" => 3,
)
);
function f($points_left, $scoring_structure, $scores_so_far = array()){
if($points_left==0){
print_score($scores_so_far);
}else if($points_left>0){
if($scoring_structure){
list($score_type, $points_for_score_type) =
first_element($scoring_structure);
// Option 1: Use a highest-denomination coin,
// and make change for the rest.
if($points_for_score_type <= $points_left){
f(
$points_left-$points_for_score_type,
$scoring_structure,
increment($scores_so_far,$score_type)
);
}
// Option 2: Attempt to make change for the full amount without
// using the highest denomination coin at all.
f(
$points_left,
all_except_first_element($scoring_structure),
$scores_so_far
);
}
}else{
exit("Error: Should never reach here!\n");
}
}
function increment($arr, $key){
$arr[$key]++;
return $arr;
}
function all_except_first_element($arr){
list($k, $v) = first_element($arr);
unset($arr[$k]);
return $arr;
}
function first_element($arr){
foreach($arr as $k=>$v){
return array($k, $v);
}
}
function print_score($scores_so_far){
$parts = array();
foreach($scores_so_far as $k=>$v){
$parts[]= "$k: $v";
}
echo implode(", ", $parts), "\n";
}
您的方法可以進一步改進-而不是查看三個變量的所有組合-嘗試,轉換和dropgoals,您只能查看不超過$score
那些組合。 盡管您仍然具有嵌套循環,但是循環內代碼的執行次數減少了。 見下文。
echo "<h1>Score: ".$score."</h1>";
$triesScore = 5;
$conversionsScore = 2;
$dropgoalsScore = 3;
for ($tries = 0; $tries <= $score/$triesScore; $tries++) {
for ($conversions = 0; $conversions <= ($score-$triesScore*$tries)/$conversionsScore; $conversions++) {
for ($dropgoals = 0; $dropgoals <= ($score-$triesScore*$tries-$conversionsScore*$conversions)/$dropgoalsScore; $dropgoals++){
$testscore = ($tries * $triesScore) + ($conversions * $conversionsScore) + ($dropgoals * $dropgoalsScore);
if ($testscore == $score) {
echo "Found a way to achieve score with ".$tries." tries ".$conversions." conversions and ".$dropgoals.($dropgoals == 0 ? " drop goals.<br />" : " drop goals or penalties.<br />");
}
}
}
}
盡管實際上,最大得分為60,但改進很小,因此可能不會引起注意。
預計算! 以為我懷疑性能會殺死您的應用程序,但以防萬一。 共有1911種可能的組合和141個有效分數,因此您可以輕松地預先計算數據,並將其存儲在磁盤上並在需要時加載它。
預計算:
$scores = array();
for ($tries = 0; $tries <= 12; $tries++) {
for ($conversions = 0; $conversions <= $tries; $conversions++) {
for ($dropgoals = 0; $dropgoals <= 20; $dropgoals++){
$score = ($tries * 5) + ($conversions * 2) + ($dropgoals * 3);
if( !array_key_exists($score,$scores) ) $scores[$score] = array();
$scores[$score][] = array( $tries, $conversions, $dropgoals );
}
}
}
echo "number of unique possible scores is " . count($scores) . "\n";
$number_combinations = 0;
foreach( $scores as $score => $combinations ) {
echo "Score " . $score . " has " . count($combinations) . " combinations\n";
$number_combinations += count($combinations);
}
echo "number of unique combinations is " . $number_combinations . "\n";
// store
file_put_contents("scores.txt",serialize($scores));
抬頭:
$scores=unserialize(file_get_contents("scores.txt"))
$number_of_combinations_for_score_23 = array_key_exists(23,$scores) ? count($scores[23]) : 0;
您甚至可以減少分數數組,使其在右側僅包含“有效或無效”布爾值。 這樣可以節省一些查找時間和空間。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.