咱們能夠用2*1的小矩形橫着或者豎着去覆蓋更大的矩形。請問用n個2*1的小矩形無重疊地覆蓋一個2*n的大矩形,總共有多少種方法?html
一開始嘗試解這道題的時候其實有些不知道怎麼下手,花了很長時間。後來才發現能夠利用遞歸的思想,將n的值不斷放小到某個能夠直接知道結果的值。雖然直接實現遞歸的算法可能效率不高,但在找到題目的遞歸解法後,再在遞歸算法的基礎上作優化,就能夠獲得一個滿意的答案。
回到本題,用n個2*1的小矩形無重疊地覆蓋一個2*n的大矩形,假設有F(n)中方法
先用一個2*1的小矩形,豎着覆蓋大矩形,以下圖所示。則還剩下2*(n-1)的大矩形須要覆蓋,即有F(n-1)種方法
算法
若是先用一個2*1的小矩形,橫着覆蓋大矩形,以下圖所示。則底部的紅色區域也只能用一個2*1的小矩形橫着覆蓋。則還剩下2*(n-2)的大矩形須要覆蓋,即有F(n-2)中方法
優化
由以上兩種狀況可知,F(n) = F(n - 1) + F(n - 2),咱們只須要知道F(0),F(1),就能夠求得F(n)。很明顯這是一個斐波那契數列的定義。對於斐波那契數列的多種求解方法能夠參考【劍指Offer】斐波那契數列
當n = 0的時候,顯然有0中覆蓋方法,即F(0) = 0
當n = 1的時候,只有一種覆蓋方法,即F(1) = 1
咱們能夠直接使用直觀的遞歸算法求解,以下所示3d
public int rectCover(int number) { if (number <= 0) return 0; if (number == 1) return 1; else if (number == 2) return 2; return rectCover(number - 1) + rectCover(number - 2); }
能夠使用循環迭代的方式優化遞歸算法,以下所示code
public int rectCoverOptimize(int number) { int f = 0, g = 1; while (number-- > 0) { g = f + g; f = g - f; } return f == 0 ? 0 : g; }
既然已經知道本題實際上就是求解斐波那契數列,那麼能夠利用矩陣的快速冪求解htm
// 矩陣乘法 public int[,] matrixMul(int[,] m1, int[,] m2) { int[,] ret = { {m1[0, 0] * m2[0,0] + m1[0, 1] * m2[1,0], m1[0, 0] * m2[0,1] + m1[0, 1] * m2[1,1]}, {m1[1, 0] * m2[0,0] + m1[1, 1] * m2[1,0], m1[1, 0] * m2[0,1] + m1[1, 1] * m2[1,1]} }; return ret; } // 矩陣快速冪 public int[,] matrixPow(int[,] m, int n) { int[,] ret = { { 1, 0 }, { 0, 1 } }; while (n > 0) { if ((n & 1)> 0){ ret = matrixMul(ret, m); } n >>= 1; m = matrixMul(m, m); } return ret; } public int rectCoverOptimize2(int number) { if (number == 0) return 0; int[,] unit = { { 1, 1 }, { 1, 0 } }; int[,] ret = matrixPow(unit, number); int[,] m = { { 1, 0 }, { 0, 0 } }; ret = matrixMul(ret, m); return ret[0,0]; }