[英]How can I optimize this 'lottery' function in PHP?
早些時候,我在Matlab中為此類彩票功能編寫了代碼,只是為了測試是否可行。 但是,實際上我在PHP中需要它,因此我只是重寫了代碼,它的確起作用了,但是由於涉及很多循環,因此我想確保自己盡可能高效地執行它。
代碼的作用是:
您可以調用函數$lotto -> type($users,$difficulty)
,它將返回兩個數字。 這就是解釋, $users
是在網站上注冊的用戶數,即可能購買票的人。 $difficulty
是介於1和10之間的數字,其中5是正常值,1是簡單值,而10是困難值。 這里的困難是指匹配彩票中的所有數字有多么困難。
那么函數返回的數字是多少? 那將是$n
和$r
。 $n
是彩票上的數字數量, $r
是您可以從彩票中選擇的數字數量。 例如,在英國,如果您選擇6,則國家彩票有49個號碼,即$n = 49
和$r = 6
。
函數如何計算這兩個數字? 在英國國家彩票中,有13,983,816種可能的彩票組合。 如果我運行$lotto -> type(13983816,1)
,它將返回array(49,6)
。 基本上,它試圖做到這一點,因此,票證組合與注冊用戶一樣多。
tl; dr,代碼如下:
<?php
class lotto {
public function type($users,$difficulty){
$current_r = $r = 2;
$current_n = 0;
$difficulty = ($difficulty + 5) / 10; // sliding scale from 1 - 10
$last_tickets_sold = 200; // tickets sold in last lotto
$last_users = 100; // how many users there were in the last lotto
$last_factor = $last_tickets_sold / $last_users; // tickets per user
$factor = $last_factor * $difficulty;
$users *= $factor;
while($r <= 10){
$u = 0;
$n = $r;
while($u < $users && $n < 50){
$u = $this -> nCr(++$n,$r);
}
if($r == 2){
$current_n = $n;
} elseif(abs($this -> nCr($n,$r) - $users) < abs($this -> nCr($current_n,$current_r) - $users)){
// this is a better match so update current n and r
$current_r = $r;
$current_n = $n;
}
$r++;
}
return array($current_n,$current_r);
}
private function nCr($n,$r){
return $this -> factorial($n) / (
$this -> factorial($r) * $this -> factorial($n - $r)
);
}
private function factorial($x){
$f = $x;
while(--$x){
$f *= $x;
}
return $f;
}
}
$lotto = new lotto;
print_r($lotto -> type(1000,5));
?>
我進行了快速掃描,發現了一些可以進一步優化的地方。
組合
您的算法是蠻力的,可以進一步優化
private function nCr($n,$r){
return $this -> factorial($n) / (
$this->factorial($r) * $this->factorial($n - $r)
);
}
至
function nCr($n,$r) {
$top = 1;
$sub = 1;
for($i = $r+1; $i <= $n; $i++)
$top *= $i;
$n -= $r;
for($i = 2; $i <= $n; $i++)
$sub *= $i;
return $top / $sub;
}
組合計算過多
計算組合是昂貴的。
$u = 0;
$n = $r;
while($u < $users && $n < 50){
$u = $this -> nCr(++$n,$r);
}
至
$n = $r + 1;
$u = nCr($n, $r);
while ($u < $users && $n < 50) {
$n++;
$u *= $n;
$u /= ($n - $r);
}
立即觀察到您有可能被0除以錯誤
$last_factor = $last_tickets_sold / $last_users;
可以通過在其周圍放一個簡單的if語句來解決
$last_factor = ($last_users == 0) ? 0 : $last_tickets_sold / $last_users;
不管對代碼進行詳細檢查,您確定循環都不需要繼續或中斷嗎?
您的算法中factorial()的范圍是[0,50],那么為什么不靜態地對此進行預計算呢?
private static $factorial=array(1);
private static genFactorial($max) {
if( count( self::$factorial ) > $max ) return;
foreach ( range(count(self::$factorial), $max) as $n ) {
self::$factorial[$n] = $i*self::$factorial[$n-1];
}
}
現在添加一個self::genFactorial(50);
__construct()
或type()
並通過self::$factorial[$n]
替換對$this -> factorial($n)
的引用。
這只是一個快速的代碼轉儲。 甚至沒有檢查過編譯,因此不能原諒任何錯別字等。但這是通過數組元素提取來替換函數調用(包括while循環)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.