遞歸與循環(斐波那契數列,位運算)

若是咱們須要重複的屢次計算相同的問題,能夠選擇遞歸循環兩種方法。算法

遞歸:是在函數的內部調用這個函數自身,而循環則是經過設置算法的初始值和終止條件,在一個範圍內重複運算。一般基於遞歸實現的代碼比基於循環實現的代碼要簡潔不少,更加易於實現。但它同時也有顯著的缺陷:遞歸因爲是函數調用自身,而函數調用是有時間和空間的消耗的(每一次函數調用,都須要在內存棧中分配空間以保存參數,返回地址以及臨時變量,而往棧裏壓入數據和彈出數據都須要時間。);另外,遞歸調用中可能有不少計算都是重複的,從而對性能帶來很大的負面影響。遞歸還有可能引發嚴重的問題:調用棧溢出。函數

斐波那契數列:寫一個函數,輸入 n,求斐波那契數列的第 n 項。性能

1. 效率低的解法(遞歸):spa

不難發現樹中有不少重複節點,並且重複的節點隨着n 的增大而急劇增長,事實上,用遞歸方法計算的時間複雜度是以 n 的指數的方式遞增的。遞歸

//遞歸求解:
int Fibonacci_1(int n)
{
 if(n == 0)
  return 0;
 if(n == 1)
  return 1;
 return Fibonacci_1(n - 1) + Fibonacci_1(n - 2);
}
內存

2. 實用的解法(循環):時間複雜度爲O(N)。ci


//循環求解
int Fibonacci_2(int n)
{
 int result[2] = {0, 1};
 if(n < 2)
  return result[n];
 int fibNMinusOne = 1;
 int fibNMinusTwo = 0;
 int fibN = 0;
 for(int i = 2; i <= n; i++)
 {
  fibN = fibNMinusOne + fibNMinusTwo;
  fibNMinusTwo = fibNMinusOne;
  fibNMinusOne = fibN;  
 }
 return fibN;
}效率

斐波那契數列的不一樣應用:變量

        1)一隻青蛙一次能夠跳上1 級臺階,也能夠跳上 2 級臺階。求該青蛙跳上一個 n 級的臺階總共有多少種跳法?循環

分析: 先考慮最簡單的情形,假設只有一級臺階時,顯然只有一種跳法。若是有兩級臺階時,那就有兩種跳法:一種是分兩次跳,每一次只跳一級臺階;另一種就是一次跳 2 級。

接着討論通常狀況,把 n 級臺階時的跳法當作是 n 的函數 F(n),當 n > 2 時,第一次跳的時候就有兩種不一樣的選擇:一是第一次只跳一級臺階,此時跳法的數目等於後面剩下的 n - 1級臺階的跳法數目,記爲F(n - 1)。另一種選擇是第一次跳 2 級,此時,跳法數目等於後面剩下的 n - 2 級臺階的跳法數目,記爲 F(n - 2)。所以,n 級臺階的不一樣跳法的總數爲 F(n) = F(n - 1) + F(n - 2)。

        2)如圖:可使用 2 * 1 (左)的小矩形橫着或者是豎着去覆蓋更大的矩形,請問用 8 * 2 * 1 的小矩形無重疊的覆蓋一個 2 * 8 的大矩形(右),總共有多少種方法?

分析:先把 2 * 8 的覆蓋方法記爲 F(8) ,用第一個 1 * 2小矩形去覆蓋大矩形的最左邊時有兩種選擇,豎着放或橫着放。當豎着放的時候,右邊還剩下 2 * 7的區域,這種狀況下的覆蓋方法記爲 F(7)。接下來考慮橫着放的狀況。當 1 * 2 的小矩形橫着放的時候,而在右邊還剩下 2 * 6 的區域,這種情形下的覆蓋方法記爲F(6)。所以, F(8) = F(7) + F(6)。【爲斐波那契數列】

(二) 位運算

問題:二進制中 1 的個數。輸入一個二進制數,輸出其中 1 的個數

分析:

一個基本思路:先判斷二進制表示中最右邊移位是否是 1, 接着把輸入的整數右移一位,此時原來處於從右邊數起的第二位被移到了最右邊,再判斷是否爲1。這樣每次移動一位,知道整個整數都變成 0 爲止。可是,此時當輸入的二進制數爲一個負數時,容易進入死循環(由於,負數右移以後,左邊補符號位 1)。爲了不死循環,能夠不右移輸入的數字 n,首先將 n 與 1 作與運算,判斷 n 的最後一位是否爲1. 接着把 1 左移一位,獲得 2,再和 n 作與運算,判斷輸入數據的第二位是否爲 1. 這樣反覆左移,每次都能判斷 n 的其中一位是否爲 1 。

int NumberOf1(int n)
{
 int count = 0;
 unsigned int flag = 1;
 while(flag)
 {
  if(n & flag)
   count++;
  flag = flag << 1;
 }
 return count;
}

經典算法:咱們發現把一個整數減去 1,都是把左右邊的 1 變成 0,若是它的右邊還有 0 的話,全部的 0 都變成 1,而它的左邊全部位都保持不變。接下來將一個二進制數和它減去 1 的結果作位於運算,會把該二進制數最右邊的 1 變成 0。那麼一個二進制數表示中,有多少個 1,就能夠進行多少次這樣的操做。


int NumberOf_1(int n)
{
 int count = 0;
 while(n)
 {
  ++count;
  n = n & (n - 1);
 }
 return count;
}

相關題目:1)輸入兩個二進制數 m 和 n ,計算須要改變 m 的多少位才能獲得 n。

                                解決方法:第一步求這兩個數的異或,第二步統計異或結果中 1 的個數。

                2)用一條語句判斷一個整數是否是 2 的整數次方。

                                解決方法:一個整數若是是 2 的整數次方,那麼它的二進制表示中有且只有一位是 1,而其餘全部位均爲 0,根據以前的分析,將這個數減去 1 以後,再和它本身作與運算,這個整數中惟一的 1 就會變成 0。

相關文章
相關標籤/搜索