脑筋急转弯
补充证明 灵茶山艾府找不到规律?请看图!(Python/Java/C++/Go)
一定要看链接里的图!本题为看图的形象证明!!
定义: d p [ n ] dp[n] dp[n] 是 2 × n 2\times n 2×n 矩形的 所有姿态 组成的状态。
一般规律:对于 i + j = n i+j=n i+j=n , d p [ n ] dp[n] dp[n] 包含 d p [ j ] dp[j] dp[j] 拼接 在 d p [ i ] dp[i] dp[i] 后组成的任何姿态。
如: n = 4 n=4 n=4 , d p [ 4 ] dp[4] dp[4] 包含 d p [ 1 ] dp[1] dp[1] 拼接在 d p [ 3 ] dp[3] dp[3] 后组成的任何姿态。
在链接中,找到新规律。从 d p [ 3 ] dp[3] dp[3] 开始,每一个新状态都会多出两种 特有姿态 。
特有姿态 s p [ i ] sp[i] sp[i] 定义:不由之前状态拼接的全新姿态。
特有姿态如下:

观察,记录 d p [ i ] dp[i] dp[i] 对应的特有姿态 s p [ i ] sp[i] sp[i],有
① s p [ 1 ] = s p [ 2 ] = 1 sp[1] = sp[2] = 1 sp[1]=sp[2]=1
② s p [ 3 ] = s p [ 4 ] = ⋯ = s p [ n ] = 2 sp[3] = sp[4] = \dots =sp[n]=2 sp[3]=sp[4]=⋯=sp[n]=2
对于 i + j = n i+j=n i+j=n ,遍历 i = n − 1 , n − 2 , n − 3 , … , 2 , 1 i = n-1,n-2,n-3,\dots ,2,1 i=n−1,n−2,n−3,…,2,1 ; j = 1 , 2 , 3 , … , n − 2 , n − 1 j = 1,2,3,\dots ,n-2,n-1 j=1,2,3,…,n−2,n−1 ,将 j j j 的特有姿态 s p [ j ] sp[j] sp[j] ,拼接在 i i i 的所有姿态 d p [ i ] dp[i] dp[i] 后,就可以 不重不漏 的组成 n n n 的所有姿态 d p [ n ] dp[n] dp[n] 。
数学证明,可以略过,看结论
(可以不看)得到递推式 ③ d p [ n ] = d p [ n − 1 ] × s p [ 1 ] + d p [ n − 2 ] × s p [ 2 ] + d p [ n − 3 ] × s p [ 3 ] + ⋯ + d p [ 1 ] × s p [ n − 1 ] dp[n] = dp[n-1]\times sp[1] + dp[n-2]\times sp[2] +dp[n-3]\times sp[3] +\dots+dp[1]\times sp[n-1] dp[n]=dp[n−1]×sp[1]+dp[n−2]×sp[2]+dp[n−3]×sp[3]+⋯+dp[1]×sp[n−1]。
①②代入③,得 d p [ n ] = d p [ n − 1 ] + d p [ n − 2 ] + 2 × d p [ n − 3 ] + 2 × d p [ n − 4 ] + ⋯ + 2 × d p [ 1 ] dp[n] = dp[n-1] + dp[n-2] + 2\times dp[n-3] + 2\times dp[n-4] +\dots +2\times dp[1] dp[n]=dp[n−1]+dp[n−2]+2×dp[n−3]+2×dp[n−4]+⋯+2×dp[1]
整理,得 ④ d p [ n ] = d p [ n − 1 ] + d p [ n − 2 ] + 2 × ( d p [ n − 3 ] + d p [ n − 4 ] + ⋯ + d p [ 1 ] ) dp[n] = dp[n-1] + dp[n-2] + 2\times (dp[n-3] + dp[n-4] +\dots + dp[1]) dp[n]=dp[n−1]+dp[n−2]+2×(dp[n−3]+dp[n−4]+⋯+dp[1])
又⑤ d p [ n − 1 ] = d p [ n − 2 ] + d p [ n − 3 ] + 2 × ( d p [ n − 4 ] + d p [ n − 5 ] + ⋯ + d p [ 1 ] ) dp[n-1] = dp[n-2] + dp[n-3] + 2\times (dp[n-4] + dp[n-5] +\dots + dp[1]) dp[n−1]=dp[n−2]+dp[n−3]+2×(dp[n−4]+dp[n−5]+⋯+dp[1])
结论
④-⑤,得 d p [ n ] − d p [ n − 1 ] = d p [ n − 1 ] + d p [ n − 3 ] dp[n] - dp[n-1] = dp[n-1]+dp[n-3] dp[n]−dp[n−1]=dp[n−1]+dp[n−3]
结论: d p [ n ] = 2 × d p [ n − 1 ] + d p [ n − 3 ] dp[n] = 2\times dp[n-1] + dp[n-3] dp[n]=2×dp[n−1]+dp[n−3]
思考过程,可以不看
(可以不看) 对于 i + j = n i+j=n i+j=n ,遍历 i = n − 1 , n − 2 , n − 3 , … , 2 , 1 i = n-1,n-2,n-3,\dots ,2,1 i=n−1,n−2,n−3,…,2,1 一定有 j = 1 , 2 , 3 , … , n − 2 , n − 1 j = 1,2,3,\dots ,n-2,n-1 j=1,2,3,…,n−2,n−1 ,将 d p [ j ] dp[j] dp[j] 拼接在 d p [ i ] dp[i] dp[i] 后,组成 n n n 的所有姿态 d p [ n ] dp[n] dp[n]。差在包含重复姿态,好在包含所有姿态。对这一步优化,发现了特有姿态 s p sp sp。
class Solution {
public:
int numTilings(int n) {
long long dp[n+10];
int mod = 1e9+7;
memset(dp,0,sizeof dp);
dp[0] = 1;
dp[1] = 1;
dp[2] = 2;
for(int i = 3;i<=n;i++) dp[i] = (2*dp[i-1] + dp[i-3])%mod;
return dp[n];
}
};
时间复杂度 : O ( n ) O(n) O(n) 。
空间复杂度 : O ( n ) O(n) O(n) 。