常見算法 - PHP

楊輝三角

/**
     * 第一種代碼實現
     * @param int $n 要求的層數
     * 理解思路:   $i代表行數; $j代表列數
     */
    public function funYH($n = 1){
        //初始化數組
        $arr = [];
        for($i = 0;$i < $n;$i++){
            //注意循環條件
            for($j = 0;$j <= $i;$j++){
                if($j == 0 || $i == $j){
                    $arr[$i][$j] = 1;
                }else {
                    $arr[$i][$j] = $arr[$i-1][$j-1]+$arr[$i-1][$j];
                }
                echo $arr[$i][$j]."\t";
            }
            echo "<br/>";
        }
    }

1、一羣猴子排成一圈,按1,2,…,n依次編號。然後從第1只開始數,數到第m只,把它踢出圈,從它後面再開始數,再數到第m只,在把它踢出去…,如此不停的進行下去,直到最後只剩下一隻猴子爲止,那隻猴子就叫做大王。要求編程模擬此過程,輸入m、n, 輸出最後那個大王的編號。

    /**
     * 約瑟夫環
     * @param $n  猴子個數
     * @param $m  第$m個踢出
     */
    function king($n, $m) {
        $monkeys = range(1, $n); //創建1到n的數組
        $i = 1;
        while (count($monkeys) > 1) {
            $sign = array_shift($monkeys);
            if ($i % $m != 0) {
                array_push($monkeys, $sign);
            }
            $i ++;
        }
        return $monkeys[0];
    }
echo king(6,3);

 

2、有一母牛,到4歲可生育,每年一頭,所生均是一樣的母牛,到15歲絕育,不再能生,20歲死亡,問n年後有多少頭牛。

function niu($y){
    static $num= 1;                    //定義靜態變量;初始化牛的數量爲1
    for ($i=1; $i <=$y ; $i++) {    
        if($i>=4 && $i<15){         //每年遞增來算,4歲開始+1,15歲不能生育
        $num++;
            niu($y-$i);               //遞歸方法計算小牛$num,小牛生長年數爲$y-$i
        }else if($i==20){          
        $num--;                             //20歲死亡減一
        }
    return $num;
}

3.抽獎算法

$proArr是一個預先設置的數組,假設數組爲:array(100,200,300,400),開始是從1,1000這個概率範圍內篩選第一個數是否在他的出現概率範圍之內, 如果不在,則將概率空間,也就是k的值減去剛剛的那個數字的概率空間,在本例當中就是減去100,也就是說第二個數是在1,900這個範圍內篩選的。這樣篩選到最終,總會有一個數滿足要求。就相當於去一個箱子裏摸東西,第一個不是,第二個不是,第三個還不是,那最後一個一定是。

function get_rand($proArr) {  
    $result = '';
    //概率數組的總概率精度
    $proSum = array_sum($proArr);
    //概率數組循環
    foreach ($proArr as $key => $proCur) {
        $randNum = mt_rand(1, $proSum);
        if ($randNum <= $proCur) {
            $result = $key;
            break;
        } else {
            $proSum -= $proCur;
        }
    }
    unset ($proArr);
    return $result;
} 
    /**
     * 其中id表示中獎等級,prize表示獎品,v表示中獎概率。注意其中的v必須爲整數,你可以將對應的獎項的v設置成0,即意味着該獎項抽中的機率是0,數組中v的總和(基數),基數越大越能體現概率的準確性。本例中v的總和爲100,那麼平板電腦對應的中獎概率就是1%,如果v的總和是10000,那中獎概率就是萬分之一了。
     */
$prize_arr = array(  
'0' => array('id'=>1,'prize'=>'平板電腦','v'=>1),  
'1' => array('id'=>2,'prize'=>'數碼相機','v'=>5),  
'2' => array('id'=>3,'prize'=>'音箱設備','v'=>10),  
'3' => array('id'=>4,'prize'=>'4G優盤','v'=>12),  
'4' => array('id'=>5,'prize'=>'10Q幣','v'=>22),  
'5' => array('id'=>6,'prize'=>'下次沒準就能中哦','v'=>50),  
); 

4.冒泡排序

function maopao($arr){
    $len = count($arr); 
    for($k=0; $k<$len-1; $k++){
        for($j=$len-1; $j>$k; $j--){
            if($arr[$j] < $arr[$j-1]){
                $temp = $arr[$j];
                $arr[$j] = $arr[$j-1];
                $arr[$j-1] = $temp;
            }
        }
    }
    return $arr;
}

 

5.快速排序

function quickSort($arr) {
    //先判斷是否需要繼續進行
    $length = count($arr);
    if($length <= 1) {
        return $arr;
    }
    //選擇第一個元素作爲基準
    $base_num = $arr[0];
    //遍歷除了標尺外的所有元素,按照大小關係放入兩個數組內
    //初始化兩個數組
    $left_array = array();  //小於基準的
    $right_array = array();  //大於基準的
    for($i=1; $i<$length; $i++) {
        if($base_num > $arr[$i]) {
            //放入左邊數組
            $left_array[] = $arr[$i];
        } else {
            //放入右邊
            $right_array[] = $arr[$i];
        }
    }
    //再分別對左邊和右邊的數組進行相同的排序處理方式遞歸調用這個函數
    $left_array = quickSort($left_array);
    $right_array = quickSort($right_array);
    //合併

    return array_merge($left_array, array($base_num), $right_array);
}

 

6.二分查找算法(折半查找算法)

function binsearch($x,$a){
    $c=count($a);
    $lower=0;
    $high=$c-1;
    while($lower<=$high){
        $middle=intval(($lower+$high)/2);
        if($a[$middle]>$x){
            $high=$middle-1;
        } elseif($a[$middle]<$x){
            $lower=$middle+1;
        } else{
            return $middle;
        }
    }
    return false;
}

 

8.字符集合:輸入一個字符串,求出該字符串包含的字符集合,並按順序排序(英文)

function set($str){
    //轉化爲數組
    $arr = str_split($str);
    //去除重複
    $arr = array_flip(array_flip($arr));
    //排序
    sort($arr);
    //返回字符串
    return implode('', $arr);
}

 

9.遍歷一個文件下的所有文件和子文件夾下的文件

function AllFile($dir){
    if($dh = opendir($dir)){
        while (($file = readdir($dh)) !== false){
            if($file !='..' && $file !='.'){
                if(is_dir($dir.'/'.$file)){
                    AllFile($dir.'/'.$file);  //如果判斷還是文件,則遞歸
                }else{  
                    echo $file;            //輸出文件名
                }
            }
        } 
    }
}

 

10.從一個標準的Url提取出文件的擴展名

function getExt($url)
  {
    $arr = parse_url($url);
    $file = basename($arr['path']);// basename函數返回路徑中的文件名部分
    $ext = explode('.', $file);
    return $ext[count($ext)-1];

  }

 

11.有個人想上一個n級的臺階,每次只能邁1級或者邁2級臺階,問:這個人有多少種方法可以把臺階走完?例如:總共3級臺階,可以先邁1級再邁2級,或者先邁2級再邁1級,或者邁3次1級總共3中方式

/**
* 斐波那契數列(Fibonacci sequence),又稱黃金分割數列、因數學家列昂納多·斐波那契(Leonardoda *Fibonacci)以兔子繁殖爲例子而引入,故又稱爲“兔子數列”,指的是這樣一個數列:1、1、2、3、5、8、*13、21、34、……在數學上,斐波納契數列以如下被以遞推的方法定義:F(1)=1,F(2)=1, F(n)=F(n-*1)+F(n-2)(n>=3,n∈N*)
*/
function jieti($num){    //實際上是斐波那契數列
    return $num < 2 ? 1 : jieti($num-1) + jieti($num-2);
}

 

12.請寫一段PHP代碼,確保多個進程同時寫入同一個文件成功

<?php
    $fp = fopen("lock.txt","w+");
    if (flock($fp,LOCK_EX)) {
        //獲得寫鎖,寫數據
        fwrite($fp, "write something");

        // 解除鎖定
        flock($fp, LOCK_UN);
    } else {
        echo "file is locking...";
    }
    fclose($fp);
?>

 

13.無限級分類

function tree($arr,$pid=0,$level=0){
    static $list = array();
    foreach ($arr as $v) {
        //如果是頂級分類,則將其存到$list中,並以此節點爲根節點,遍歷其子節點
        if ($v['pid'] == $pid) {
            $v['level'] = $level;
            $list[] = $v;
            tree($arr,$v['id'],$level+1);
        }
    }
    return $list;
}

 

14.獲取上個月第一天 和 最後一天

//獲取上個月第一天
    date('Y-m-01',strtotime('-1 month'));

    //獲取上個月最後一天
    date('Y-m-t',strtotime('-1 month'));

 

18 用PHP實現一個雙向隊列

<?php
    class Deque{
    private $queue=array();
    public function addFirst($item){
        return array_unshift($this->queue,$item);
    }

    public function addLast($item){
        return array_push($this->queue,$item);
    }
    public function removeFirst(){
        return array_shift($this->queue);
    }

    public function removeLast(){
        return array_pop($this->queue);
    }
}
?>

 

21 洗牌算法

<?php
    $card_num = 54;//牌數
    function wash_card($card_num){
        $cards = $tmp = array();
        $tmp = range(1, 54);

        for($i = 0;$i < $card_num;$i++){
            $index = rand(0,$card_num-$i-1);
            $cards[$i] = $tmp[$index];
            unset($tmp[$index]);
            $tmp = array_values($tmp);
        }
        return $cards;
    }
    // 測試:
    print_r(wash_card($card_num));
?>

 

【程序1】   題目:古典問題:有一對兔子,從出生後第3個月起每個月都生一對兔子,小兔子長到第四個月後每個月又生一對兔子,假如兔子都不死,問每個月的兔子總數爲多少?   

1.程序分析:   兔子的規律爲數列1,1,2,3,5,8,13,21....   

2  就是第三個數是前兩個數字的和,既是經典的菲波那切數列

    function actionFblist($n)
    {
        // 1,1,2,3,5,8,13
    // $n 爲第n個月
        $arr = [1,1];
        if($n < 2)
            return false;


        for ($i=2;$i<=$n+1;$i++)
        {
            $arr[$i] = $arr[$i-1] + $arr[$i-2];
        }
        var_dump($arr);
        echo $arr[$n+1];
    }

 

【程序2】   題目:判斷101-200之間有多少個素數,並輸出所有素數。   
1.程序分析:判斷素數的方法:用一個數分別去除2到n-1,如果能被整除,   
則表明此數不是素數,反之是素數。  

public function actionIsPrimeNumber()
{
    $arr = [];
    for ($i=101;$i<=200;$i++)
    {
        $flag = true;
        for ($j = 2;$j < $i;$j++)
        {
            if($i % $j == 0)
            {
                $flag = false;
            }
        }

        if($flag == true)
            $arr[] = $i;
    }
    var_dump($arr);
}

 

【程序3】   題目:打印出所有的 "水仙花數 ",所謂 "水仙花數 "是指一個三位數,其各位數字立方和等於該數本身。例如:153是一個 "水仙花數 ",因爲153=1的三次方+5的三次方+3的三次方。   

1.程序分析:利用for循環控制100-999個數,每個數分解出個位,十位,百位。   

public function actionWaterFlower()
{
    $re = [];
    for($i = 100;$i<= 999;$i++)
    {
        $hundred = floor($i / 100 );     // 獲取百位數字
        $ten = floor(($i %100 ) / 10 );  // 獲取十位數字
        $one = floor($i % 100 % 10);     // 獲取各位數字

        if((pow($hundred,3)  + pow($ten,3) + pow($one,3) ) == $i )
        {
            $re[] = $i;
        }
    }
    var_dump($re);

}

 

【程序5】   題目:求s=a+aa+aaa+aaaa+aa...a的值,其中a是一個數字。例如2+22+222+2222+22222(此時共有5個數相加),幾個數相加有鍵盤控制。   

1.程序分析:關鍵是循環獲得計算出每一項的值。

2. 可以使用php的str_repeat函數  

  public function actionRepeatN()
    {
        $a = 8;
        $n = 8;
        $sum = 0;

        for ($i = 0;$i<$n;$i++)
        {
            $num = 0;
            for ($j = 0;$j<=$i;$j++)
            {
                $num += $a* pow(10,$j);
            }
            $sum += $num;
        }
        var_dump($sum);
    }

 

【程序6】題目:一個整數,它加上100後是一個完全平方數,加上168又是一個完全平方數,請問該數是多少?   

1.程序分析:在10萬以內判斷,先將該數加上100後再開方,再將該數加上168後再開方,如果開方後的結果滿足如下條件,即是結果。

public function actionWhitchNum()
{
    for ($i=1;$i<=100000;$i++)
    {
        if(pow((int)sqrt($i+100),2) == ($i+100) &&pow((int)sqrt($i+168),2) == ($i+168) )
        {
            echo $i;
        }
    }
    echo 'ok';
}

 

【程序9】 題目:輸出9*9口訣。   
1.程序分析:分行與列考慮,共9行9列,i控制行,j控制列。   

public function actionMultiplicationTable()
{
    for ($i=1;$i<=9;$i++)
    {
        for ($j=1;$j<=$i;$j++)
        {
            echo $j . '*' .$i .'=' . $i*$j;
            echo ' ';
        }
        echo "<br>";
    }
}

 

【程序10】   題目:有一分數序列:2/1,3/2,5/3,8/5,13/8,21/13...求出這個數列的前20項之和。   
1.程序分析:請抓住分子與分母的變化規律。  

public function actionAddFraction()
{
    $sum = 0;
    $numerator = [2,3];
    $denominator = [1,2];
    // 根據規律獲得所有的分子和分母
    for ($i=2;$i<20;$i++)
    {
        $numerator[$i] = $numerator[$i-2] + $numerator[$i-1];
        $denominator[$i] = $denominator[$i-2] + $denominator[$i-1];
    }
    // 獲得分數的前n項和
    for ($i=0;$i<20;$i++)
    {
        $sum += $numerator[$i] / $denominator[$i];
    }
    var_dump($sum);
}

 

【程序11】   題目:求1+2!+3!+...+20!的和   
1.程序分析:此程序只是把累加變成了累乘。   

public function actionAddFactorial()
{
    $n = 20;
    $sum = 0;
    for ($i=1;$i<=$n;$i++)
    {
        $num = 1;
        for ($j=1;$j<=$i;$j++)
        {
            $num = $j*$num;
        }
        $sum += $num;
    }
    var_dump($sum);
}

 

【程序12】   題目:利用遞歸方法求5!。   
1.程序分析:遞歸公式:fn=fn_1*4!   

public function numFactorial($n)
{
    if($n>1)
        return $sum = $n * $this->numFactorial($n-1);   // 需要注意這點,若是寫成函數要替換成函數形式
    else
        return $n;
}
public function actionNumFactorial()
{
    $n =4;
    $sum =  $this->numFactorial($n);                   // 調用上面的階乘方法(函數)
}

 

【程序13】   題目:有5個人坐在一起,問第五個人多少歲?他說比第4個人大2歲。問第4個人歲數,他說比第3個人大2歲。問第三個人,又說比第2人大兩歲。問第2個人,說比第一個人大兩歲。最後問第一個人,他說是10歲。請問第五個人多大?   

1.程序分析:利用遞歸的方法,遞歸分爲回推和遞推兩個階段。要想知道第五個人歲數,需知道第四人的歲數,依次類推,推到第一人(10歲),再往回推。   

public function myAge($n)
{
    if($n == 1)
        return $age = 10;
    else
        return 2 + $this->myAge($n-1);
}

public function actionMyAge1()
{
    $n = 5;
    echo $this->myAge($n);
}

 

【程序14】   題目:給一個不多於5位的正整數,要求:一、求它是幾位數,二、逆序打印出各位數字。 

public function actionIntLength()
{
    $num = 1232345;
    $num = (string) $num;
    $length = strlen($num);
    $numstring = '';
    for ($i=$length-1;$i>=0;$i--)
    {
        $numstring .= $num[$i];
    }
    echo $numstring;
}

 

【程序15】   題目:一個5位數,判斷它是不是迴文數。即12321是迴文數,個位與萬位相同,十位與千位相同。   

public function actionIsPalindromeNumber()
{
    $num = 12321;
    $num = (string) $num;
    if($num[0] == $num[4] && $num[1] == $num[3])
        var_dump('Is Palindrome Number');
    else
        echo 'false';
}

/*
 * 找到所有的5位的迴文數
 * */
public function actionAllPalindromeNumber()
{
    $result = [];
    for ($i=10000;$i<99999;$i++)
    {
        $i = (string) $i;
        if($i[0] == $i[4] && $i[1] == $i[3])
            $result[] = $i;
    }
    var_dump($result);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章