斐波拉契數列、漢諾塔,青蛙跳臺階 的算法實現
一.斐波那契數列 (1,1,2,3,5,8,13,21,34 ......)
f(n)=⎧⎩⎨⎪⎪0,1,f(n−1)+f(n−2),n=0n=1n>2
- 遞歸解法(效率很低)
public function Fibonacci1($n)
{
if($n <= 0){ return 0;}
if($n == 1){ return 1; }
return Fibonacci1($n - 1) + Fibonacci1($n - 2);
}
2 循環解法:改進的算法:從下往上計算。首先根據f(0)和f(1)算出f(2),再根據f(1)和f(2)算出f(3)。。。。。依此類推就可以算出第n項了。很容易理解,這種思路的時間複雜度是o(n)。實現代碼如下:
public function Fibonacci($n)
{
int $result[2] = {0 , 1};
if($n < 2)
return $result[$n];
$one= 1;
$tow= 0;
for($i = 2 ; $i <= $n ; ++$i)
{
$fibN = $one+ $tow;
$tow= $one;
$one= $fibN;
}
return $fibN;
}
二.漢諾塔
簡單的用
php實現了漢諾塔問題的求解,使用遞歸調用,但是用php實現要是盤子的個數很多的話,運行起來會很慢的...
漢諾塔主要是有三個塔座X,Y,Z,要求將三個大小不同,依小到大編號爲1,2.....n的圓盤從A移動到塔座Z上,要求
(1):每次只能移動一個圓盤
(2):圓盤可以插到X,Y,Z中任一塔座上
(3):任何時候不能將一個較大的圓盤壓在較小的圓盤之上
主要是運用了遞歸的思想,這裏使用php做個簡單的實現......
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
<?php
function hanoi( $n , $x , $y , $z ){
if ( $n ==1){
move( $x ,1, $z );
} else {
hanoi( $n -1, $x , $z , $y );
move( $x , $n , $z );
hanoi( $n -1, $y , $x , $z );
}
}
function move( $x , $n , $z ){
echo 'movedisk' . $n . 'from' . $x . 'to' . $z . '<br>' ;
}
hanoi(10, 'x' , 'y' , 'z' );
?>
|
三.青蛙跳
一隻青蛙一次可以跳上1級臺階,也可以跳上2級。求該青蛙跳上一個n級的臺階總共有多少種跳法。
與斐波那契數列不同的是,其初始值定義稍有不同,
當n=1時,只能跳一級臺階,一種跳法
當n=2時,一次跳一級或兩級,兩種跳法
所以,關於青蛙跳臺階的定義如下:
假設n級臺階是f(n)的一個函數 ,當n = 1時候只有一種跳法,n=2時候 可以一次跳1臺階 ,也可以一次跳兩個臺階 有兩種跳法,但是當n>2時,第一次跳有兩種不同的選擇,選擇跳一個臺階,那麼就剩餘f(n-1)種選擇,如果第一次跳2臺階 接下來有f(n-2)種選擇跳臺階,所以n級臺階的不同跳法f(n)=f(n-)+f(n-2)
f(n)=⎧⎩⎨⎪⎪1,2,f(n−1)+f(n−2),n=1n=2n>2
- 非遞歸寫法(借鑑)
long long FrogJump12Step(int n)
{
if (n <= 0)
{
std::cerr << "param error" << std::endl;
return -1;
}
if (n == 1)
return 1;
if (n == 2)
return 2;
int frogNMinusOne = 2;
int frogNMinusTwo = 1;
int frogN = 0;
for (unsigned int i = 3; i <= n;++i)
{
frogN = frogNMinusOne + frogNMinusTwo;
frogNMinusTwo = frogNMinusOne;
frogNMinusOne = frogN;
}
return frogN;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 遞歸解法(借鑑)
long long FrogJump12StepRecursive(int n)
{
if (n <= 0)
{
std::cerr << "param error" << std::endl;
return -1;
}
if (n == 1)
return 1;
if (n == 2)
return 2;
return FrogJump12StepRecursive(n - 1) + FrogJump12StepRecursive(n - 2);
}
四.青蛙跳升級版:
一隻青蛙一次可以跳上1級臺階,也可以跳上2級......它也可以跳上n級,此時該青蛙跳上一個n級的臺階總共有多少種跳法?
按照上面的推理:
n = 1 時, 只有一種跳法 f(n) = 1;
n = 2 時 , 有兩種跳法,第一次跳一個臺階 ,第一次跳2臺階f(2) = f(1) + f(0) = 2;
n = 3 時,f(n)= 3;第一次跳1個臺階,就剩餘f(3-1) 跳法,第一次跳二臺階,就剩餘f(3-2) ,第一次跳出3臺階,後面還有f(3-3) ,f(3) = f(2)+f(1)+f(0) = 4
......
n = n ,第一次共有n種跳法,第一次跳1臺階,後面還有f(n-1),第一次跳2,後面還有f(n-2),第一次跳3 ,後面還有f(n-3),。。。。。。,第一次跳n臺階,後面還有f(n-n)
f(n) = f(n-1) + f(n-2) + f(n-3) + f(n-4) + ......+f(n-n);
因爲
f(n-1) = f(n-2) + f(n-3) + f(n-4) + ......+f(n-n);
=> f(n) -f(n-1) = f(n-1)
=> f(n) = 2f(n-1) n>2
f(n)=⎧⎩⎨⎪⎪1,2,2∗f(n−1),n=1n=2n>2
所以:f(n)=2∗f(n−1)=2∗2(n−2)....=2n−1∗f(0)=2n−1
- 非遞歸解法:
public function FrogJump12nStep($n)
{
if ($n <= 0)
{
return -1;
}
else if (n == 1)
return 1;
else
{
$fn1 = 1;
$fn = 0;
for ($i = 2; $i <= $n;++$i)
{
$fn = 2 * $fn1;
$fn1 = $fn;
}
return $fn;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 遞歸解法
public function FrogJump12nStepRecursive($n)
{
if ($n <= 0)
{
return -1;
}
else if ($n == 1)
return 1;
else if ($n == 2)
return 2;
else
return 2 * FrogJump12nStepRecursive($n - 1);
}