import java.util.*;
/**
* NC268 矩形覆盖
* @author d3y1
*/
public class Solution {
public int rectCover(int target) {
// return solution1(target);
return solution2(target);
// return solution3(target);
// return solution4(target);
}
/**
* 数学法
*
* 举例子找规律(画图) => 2个2*1的小矩形横放看做一个整体(日字形) => 转化为 日字形与小矩形竖放的组合数
* 可得:
* F(n) = C(n,0) + C(n-1,1) + C(n-2,2) + ... + C(n-n/2,n/2)
*
* @param target
* @return
*/
private int solution1(int target){
if(target == 0){
return 0;
}
int result = 0;
for(int i=0; i<=target/2; i++){
result += C(target-i, i);
}
return result;
}
// C(n,k)
private long C(int n, int k){
k = Math.max(k, n-k);
long up=1,down=1;
for(int i=1; i<=n-k; i++){
up *= n-i+1;
down *= i;
}
return up/down;
}
/**
* 动态规划
*
* 举例子找规律(画图) => 2个2*1的小矩形横放看做一个整体(日字形)
* 可得:
* F(1) = 1
* F(2) = 2
* F(3) = 3 = 1 + 2
* F(4) = 5 = 2 + 3
* F(5) = 8 = 3 + 5
* F(6) = 13= 5 + 8
* ...
* F(n) = F(n-1) + F(n-2) , n>=3
*
* 结合图形理解F(n):
* F(n-1)里每个方案最右边竖放一个小矩形
* F(n-2)里每个方案最右边横放两个小矩形(日字形)
*
* dp[i]表示有i个小矩形时的覆盖方法数
*
* dp[i] = dp[i-1] + dp[i-2] , i>=3
*
* @param target
* @return
*/
private int solution2(int target){
if(target == 0){
return 0;
}
if(target == 1){
return 1;
}
int[] dp = new int[target+1];
dp[1] = 1;
dp[2] = 2;
for(int i=3; i<=target; i++){
dp[i] = dp[i-1] + dp[i-2];
}
return dp[target];
}
/**
* 动态规划: 空间优化
* @param target
* @return
*/
private int solution3(int target){
if(target == 0){
return 0;
}
if(target == 1){
return 1;
}
if(target == 2){
return 2;
}
int result = 0;
int head = 1, pre = 2;
for(int i=3; i<=target; i++){
result = pre + head;
head = pre;
pre = result;
}
return result;
}
/**
* 递归
* @param target
* @return
*/
private int solution4(int target){
if(target == 0){
return 0;
}
return F(target);
}
/**
* F(n)
* @param n
* @return
*/
private int F(int n){
if(n == 1){
return 1;
}
if(n == 2){
return 2;
}
return F(n-1)+F(n-2);
}
}